Problem and nearby solution image:
Problem: A mesh equally distant from each node. Each small node of grid is a circle(fig: grey circle) of radius r, if we make any circle(fig:blue color) then how can we make a set of that circle having upper(fig:red circle) and lower bound(fig:red circle). Basically we need to find upper bound radius, and lower bound radius.
Value known are:
Radius of small circle(grey) r.
Distance between two grey circle/node_of_grid from center to center = 4 X r.
Radius of big circle (blue) rb. //this may vary but will be in multiple of r. In this figure case is diameter d = 2(20 x r).
Center of big circle can only be center of small circle.
How can i find the radius of upper circle and lower circle. Each blue small circle who comes within the big circle circumference should come under upper bound and vice versa for lower bound.
Currently i came up with this solution which is incorrect :
unpper_bound_radius = rb + (r + (rb/(3.1415926 * 2r)))
lower_bound_radius = rb - (r + (rb/(3.1415926 * 2r)))
Thanks
If you're looking for an algorithm to decide which grey dots intersect with the blue circle, and calculate the radius of the boundaries that contain the selected grey dots, you could do something like this:
Give the inner and outer boundary a radius equal to the blue circle.
The grey dot straight above the center, which intersect with the blue circle or is just above it, is the starting point.
Calculate the distance from that point to the center point; if it is between rb-r and rb+r, the blue circle intersects with this grey dot.
If it intersects, adjust the inner boundary to distance - r and the outer boundary to distance + r as necessary.
If it doesn't, and the distance is greater, try the grid point below it; if it doesn't, and the distance is smaller, try the grid point to the right.
Do this until you move out of a 45° sector; you only need to check one eigth of the circle, the other results will be symmetrical.
Example calculation:
The first grid point, at the top, is 5×4r from the center; the boundaries are at 5×4r-r and 5×4r+r.
The next grid point to the right is at 5.09902×4r from the center, so the outer boundary increases to 5.09902×4r+r.
The next grid point to the right is at 5.38516×4r from the center, which is 1.54066×r outside the blue circle (too far).
The next grid point downward is at 4.47216×4r from the center, which is 1.88854×r inside the blue circle (too close).
The next grid point to the right is at exactly 5×4r from the center, so the boundaries don't change.
The next grid point to the right is at 5.65686×4r from the center, which is 2.62742×r outside the blue circle (too far).
The next grid point down is more than 45° to the right.
Result: inner boundary is at 5×4r-r, outer boundary is at 5.09902×4r+r.
function boundaries(b) {
var i = b, o = b, x = 0, y = Math.ceil(b / 4) * 4;
while (Math.atan2(y, x) >= Math.PI / 4) {
var d = Math.sqrt(x * x + y * y);
if (d < b - 1) x += 4; // too close, go right
else if (d > b + 1) y -= 4; // too far, go down
else { // intersection
if (i > d - 1) i = d - 1; // adjust inner
if (o < d + 1) o = d + 1; // adjust outer
x += 4; // go right
}
}
return {i: i, o: o};
}
var res = boundaries(20);
document.write("inner: r×" + res.i + "<br>outer: r×" + res.o);
Related
I am trying to implement an algorithm that will align a rectangle on an ellipse when a point is dragged.
The data I have is:
I know what corner is being dragged
the starting position of it
the ending position of it
My old algorithm was to align the adjacent corners, but that only worked if the ellipse or rectangle weren't at an angle.
I am trying to implement something like Figma does:
My current idea is to take the sides that were changed on drag and match the other sides that weren't changed to the size of the changed sides. Though I'm not sure if that's correct.
Let rectangle is described by center point (CX, CY) and two unit direction vectors (WX, WY) and (HX, HY), also W is half-width, H is half-height.
As far as I understand, rectangle slope is preserved, so direction vectors remain the same.
When corner number k was shifted, it's new position is (NX, NY). Opposite vertex has number (k+2)%4 and it's position is (PX, PY) (doesn't change)
New center is
CX' = (PX + NX) / 2
CY' = (PY + NY) / 2
New half-width and half-height
W' = 0.5 * Abs(WX * (NX - PX) + WY * (NY - PY))
H' = 0.5 * Abs(HX * (NX - PX) + HY * (NY - PY))
Given the center, radius and and 3 points on a circle, I want to draw an arc that starts at the first point, passing through the second and ends at the third by specifying the angle to start drawing and the amount of angle to rotate. To do this, I need to calculate the points on the arc. I want the number of points calculated to be variable so I can adjust the accuracy of the calculated arc, so this means I probably need a loop that calculates each point by rotating a little after it has calculated a point. I've read the answer to this question Draw arc with 2 points and center of the circle but it only solves the problem of calculating the angles because I don't know how 'canvas.drawArc' is implemented.
This question has two parts:
How to find the arc between two points that passes a third point?
How to generate a set of points on the found arc?
Let's start with first part. Given three points A, B and C on the (O, r) circle we want to find the arc between A and C that passes through B. To find the internal angle of the arc we need to calculate the oriented angles of AB and AC arcs. If angle of AB was greater than AC, we are in wrong direction:
Va.x = A.x - O.x;
Va.y = A.y - O.y;
Vb.x = B.x - O.x;
Vb.y = B.y - O.y;
Vc.x = C.x - O.x;
Vc.y = C.y - O.y;
tb = orientedAngle(Va.x, Va.y, Vb.x, Vb.y);
tc = orientedAngle(Va.x, Va.y, Vc.x, Vc.y);
if tc<tb
tc = tc - 2 * pi;
end
function t = orientedAngle(x1, y1, x2, y2)
t = atan2(x1*y2 - y1*x2, x1*x2 + y1*y2);
if t<0
t = t + 2 * pi;
end
end
Now the second part. You said:
I probably need a loop that calculates each point by rotating a little
after it has calculated a point.
But the question is, how little? Since the perimeter of the circle increases as its radius increase, you cannot reach a fixed accuracy with a fixed angle. In other words, to draw two arcs with the same angle and different radii, we need a different number of points. What we can assume to be [almost] constant is the distance between these points, or the length of the segments we draw to simulate the arc:
segLen = someConstantLength;
arcLen = abs(tc)*r;
segNum = ceil(arcLen/segLen);
segAngle = tc / segNum;
t = atan2(Va.y, Va.x);
for i from 0 to segNum
P[i].x = O.x + r * cos(t);
P[i].y = O.y + r * sin(t);
t = t + segAngle;
end
Note that although in this method A and C will certainly be created, but point B will not necessarily be one of the points created. However, the distance of this point from the nearest segment will be very small.
We have a set of circles in a rectangular area, all the circles have the same radii, I want to find the circles totally covered by other circles.
is there any algorithme for that ?
Geometry
First, find all the circles whose center is closer than 2×r to the center of the main circle; circles further away do not overlap.
Example: the main (black) circle and 3 overlapping circles.
Then, to know that the main circle is completely covered, you have to find a set of circles for which every intersecting point of two circles which lies within the main (black) circle, is covered by a third circle.
Algorithm
Practically, you start with 2 circles (e.g. blue and red), and find the 2 points where they intersect (purple dots). If one or both points are within the main (black) circle, then these points have to be covered by an additional circle.
Then, one by one, add an additional circle (e.g. green), and see whether it covers non-covered points (in the example it does). However, this new circle adds new intersection points with the other circles already in the set (blue and red); find these points (teal and brown dots) and check whether they are covered by any of the circles (the teal one is covered by the red circle, but the brown one is not covered by the blue circle).
Keep adding circles to the set until every intersection point inside the main (black) circle is covered by another circle in the set (in which case the whole main circle is covered), or until you run out of circles (in which case the main circle is not completely covered).
Special cases:
If one of the circles has the exact same center point as the main circle, it covers the main circle on its own.
If none of the circles have intersection points inside the main circle, the main circle is not covered.
Code example
This code example demonstrates how to find the intersecting points of two circles, which takes care of most of the geometry needed in the algorithm.
function intersections(p, q, r) {
var d = distance(p, q);
if (d > 2 * r) return [];
var m = middle(p, q);
if (d == 2 * r) return [m];
var a = angle(p, q) + Math.PI / 2;
var l = length(d, r);
return [{x: m.x + l * Math.cos(a), y: m.y + l * Math.sin(a)},
{x: m.x - l * Math.cos(a), y: m.y - l * Math.sin(a)}];
function distance(p, q) {
return Math.sqrt(Math.pow(p.x - q.x, 2) + Math.pow(p.y - q.y, 2));
}
function middle(p, q) {
return {x: (p.x + q.x) / 2, y: (p.y + q.y) / 2};
}
function angle(p, q) {
return Math.atan2(q.y - p.y, q.x - p.x);
}
function length(d, r) {
return Math.sqrt(Math.pow(r, 2) - Math.pow(d, 2) / 4);
}
}
document.write(JSON.stringify(intersections({x:1, y:2}, {x:3, y:-4}, 5)));
For example, if I have 2 rectangles, the anchor point is in the centre of the rectangle, one the width is 6 (Red), another is 2 (blue), I want to align them horizontally to the centre like this:
So that the position(also the centre and anchor point) of whole structure is at the origin, the red rectangle should be placed at (-1,0), and the blue rectangle should be placed at (3,0).
This example can be solved by graph and divided into 1 unit segments, but how about if I have arbitrary numbers of rectangles with different width?
How to find the position of each rectangle which the anchor point of each rectangle is at the centre?
Sum the widths of all the rectangles and then divide by 2. This is the distance from the left side of the left-most rectangle to center.
Then for each rectangle, compute the distance from the left side of the left-most rectangle to the rectangle's center point. Subtract this from the first number to find the offset of the rectangle's center point from the center.
Pseudo-code:
Find distance from the left side of the left-most rectangle to center:
int i;
float sum = 0;
for(i = 0; i < rectangle_count; i++)
sum += rectangles[i].width;
centerpoint = sum / 2.0;
Compute offset of each rectangle from center:
sum = 0.0;
for(i = 0; i < rectangle_count; i++)
{
// compute offset for this rectangle relative to center:
rectangles[i].offset = (sum + (rectangles[i].width / 2.0)) - centerpoint;
sum += rectangles[i].width;
}
Let's say there are n small rectangles and call them r0, r1, ..., rn-1. Furthermore, let's assume we're laying them out left to right. Let's call the larger rectangle formed by putting them all end to end R, and assume we have a function w(r) that computes the width of a rectangle.
We know that the left side of R will have an x-coordinate of -w(R)/2. That will also be the x coordinate of r0, let's call this x-coordinate l0. You know that the x-coordinate of the left hand side of r1 will be moved over by one width of r0. In other words, l1 = w(r0) + l0. Likewise, you know that the x-coordinate of the left hand side of r2 will be at l2 = w(r1) + l1. In general, li = w(ri-1) + li-1.
In plain english, you're calculating the position of the left hand side of the first rectangle and adding its width to find the left hand side of the next one and repeating that process until you know the position of the left hand side of every rectangle.
Now the only difficulty is to find the x-coordinate of the center of each rectangle. But you already know the x-coordinate of left hand side for each one, so just move over half its width to the right. That is ci = li + w(i)/2, where ci is the x-coordinate of the center of ri.
I'm trying to code a general algorithm that can find a polygon from the area swept out by a circle (red line) that follows some known path (green line), and where the circle gets bigger as it moves further down the known path. Basically, can anyone point me down a direction to solve this, please? I can't seem to nail down which tangent points are part of the polygon for any point (and thus circle) on the path.
Any help is appreciated.
Well, the easiest is to approximate your path by small segments on which your path is linear, and your circle grows linearly.
Your segments and angles will likely be small, but for the sake of the example, let's take bigger (and more obvious) angles.
Going through the geometry
Good lines for the edges of your polygon are the tangents to both circles. Note that there aren't always close to the lines defined by the intersections between the circles and the orthogonal line to the path, especially with stronger growth speeds. See the figure below, where (AB) is the path, we want the (OE) and (OF) lines, but not the (MN) one for example :
The first step is to identify the point O. It is the only point that defines a homothetic transformation between both circles, with a positive ratio.
Thus ratio = OA/OB = (radius C) / (radius C') and O = A + AB/(1-ratio)
Now let u be the vector from O to A normalized, and v a vector orthogonal to u (let us take it in the direction from A to M).
Let us call a the vector from O to E normalized, and beta the angle EOA. Then, since (OE) and (AE) are perpendicular, sin(beta) = (radius C) / OA. We also have the scalar product a.u = cos(beta) and since the norm of a is 1, a = u * cos(beta) + v * sin(beta)
Then it comes easily that with b the vector from O to F normalized, b = u * cos(beta) - v * sin(beta)
Since beta is an angle less than 90° (otherwise the growth of the circle would be so much faster than it going forward, that the second circle contains the first completely), we know that cos(beta) > 0.
Pseudo-code-ish solution
For the first and last circles you can do something closer to them -- fort the sake of simplicity, I'm just going to use the intersection between the lines I'm building and the tangent to the circle that's orthogonal to the first (or last) path, as illustrated in the first figure of this post.
Along the path, you can make your polygon arbitrarily close to the real swept area by making the segments smaller.
Also, I assume you have a function find_intersection that, given two parametric equations of two lines, returns the point of intersection between them. First of all, it makes it trivial to see if they are parallel (which they should never be), and it allows to easily represent vertical lines.
w = 1; // width of the first circle
C = {x : 0, y : 0}; // first circle center
while( (new_C, new_w) = next_step )
{
// the vector (seg_x, seg_y) is directing the segment
seg = new_C - C;
norm_seg = sqrt( seg.x * seg.x + seg.y * seg.y );
// the vector (ortho_x, ortho_y) is orthogonal to the segment, with same norm
ortho = { x = -seg.y, y = seg.x };
// apply the formulas we devised : get ratio-1
fact = new_w / w - 1;
O = new_C - seg / fact;
sin_beta = w * fact / norm_seg;
cos_beta = sqrt(1 - sin_beta * sin_beta);
// here you know the two lines, parametric equations are O+t*a and O+t*b
a = cos_beta * seg + sin_beta * ortho;
b = cos_beta * seg - sin_beta * ortho;
if( first iteration )
{
// initialize both "old lines" to a line perpendicular to the first segment
// that passes through the opposite side of the circle
old_a = ortho;
old_b = -ortho;
old_O = C - seg * (w / norm_seg);
}
P = find_intersection(old_O, old_a, O, a);
// add P to polygon construction clockwise
Q = find_intersection(old_O, old_b, O, b);
// add Q to polygon construction clockwise
old_a = a;
old_b = b;
old_O = O;
w = new_w;
C = new_C;
}
// Similarly, finish with line orthogonal to last direction, that is tangent to last circle
O = C + seg * (w / norm_seg);
a = ortho;
b = -ortho;
P = find_intersection(old_O, old_a, O, a);
// add P to polygon construction clockwise
Q = find_intersection(old_O, old_b, O, b);
// add Q to polygon construction clockwise
Let's suppose the centers are along the positive x-axis, and the lines in the envelope are y=mx and y=-mx for some m>0. The distance from (x,0) to y=mx is mx/sqrt(1+m^2). So, if the radius is increasing at a rate of m/sqrt(1+m^2) times the distance moved along the x-axis, the enveloping lines are y=mx and y=-mx.
Inverting this, if you put a circle of radius cx at the center of (x,0), then c=m/sqrt(1+m^2) so
m = c/sqrt(1-c^2).
If c=1 then you get a vertical line, and if c>1 then every point in the plane is included in some circle.
This is how you can tell how much faster than sound a supersonic object is moving from the Mach angle of the envelope of the disturbed medium.
You can rotate this to nonhorizontal lines. It may help to use the angle formulation mu = arcsin(c), where mu is the angle between the envelope and the path, and the Mach number is 1/c.