Positioning random points on a 2D plane - geometry

So here's a little bit of geometry for you. I've been stuck on this for a while now:
I need to write a script (in C#, but feel free to answer in whatever script you'd like) that generates random points. A points has to values, x and y.
I must generate N points total (where N > 1 and is also randomly up to 100).
point 1 must be x = 0, y = 0. point 2 must be of distance 1 from point 1. So that Root(x2 + y2) = 1.
point 3 must be of distance 1 from point 2 and so on and so forth.
Now here's the tricky part - point N must be of distance 1 from point 1. So if you were to connect all points into a single shape, you'd get a closed shape with each vertices being the same length.
(vertices may cross and you may even have two points at exactly the same location. As long as it's random).
Any idea how you'd do that?

I would do it with simulation of chain there are 2 basic ways one is start from regular polygon and then randomize one point a bit (rotate a bit) then iterate the rest to maintain the segment size=1.
The second one is start with full random open chain (like in MBo answer) and then iteratively change the angles until the last point is on desired distance from first point. I think the second approach is a bit simpler to code...
If you want something more complicated then you can generate M random points and handle them as closed Bezier curve cubic patches loop control points. Then just find N equidistant points on it (this is hard task) and rescale the whole thing to match segment line size = 1
If you want to try first approach then
Regular polygon start (closed loop)
Start with regular polygon (equidistant points on circle). So divide circle to N angular segments. Select radius r so line length match l=1
so r=0.5/cos(pi/N) ... from half angle triangle
Make function to rotate i-th point by some single small step
So just rotate the i-th point around (i-1)th point with radius 1 and then iteratively change the {i+1,...N} points to match segments sizes
you can exploit symmetry to avoid bullet #2
but this will lead not to very random result for small N. Just inverse rotation of 2 touching segments for random point p(i) and loop this many times.
to make it more random you can apply symmetry on whole parts (between 2 random points) instead of on 2 lines only
The second approach is like this:
create randomized open chain (like in MBo's answer)
so all segments are already with size=1.0. Remember also the angle not just position
i-th point iteration
for simplicity let the points be called p1,p2,...pn
compute d0=||pn-p1|-1.0|
rotate point pi left by some small da angle step
compute dl=||pn-p1|-1.0|
rotate point pi right by 2.0*da
compute dr=||pn-p1|-1.0|
rotate point pi to original position ... left by da
now chose direction closer to the solution (min dl,dr,d0) so:
if d0 is minimal do not change this point at all and stop
if dl is minimal then rotate left by da while dl is lowering
if dr is minimal then rotate right by da while dr is lowering
solution
loop bullet #2 while the d=||pn-p0|-1.0| is lowering then change da to da*=0.1 and loop again. Stop if da step is too small or no change in d after loop iteration.
[notes]
Booth solutions are not precise your distances will be very close to 1.0 but can be +/- some error dependent on the last da step size. If you rotate point pi then just add/sub angle to all pi,pi+1,pi+2,..pn points

Edit: This is not an answer, closeness has not been taken into account.
It is known that Cos(Fi)^2 + Sin(Fi)^2 = 1 for any angle Fi
So you may use the next approach:
P[0].X = 0
P[0].Y = 0
for i = 1 .. N - 1:
RandomAngle = 2 * Pi * Random(0..1)
P[i].X = P[i-1].X + Cos(RandomAngle)
P[i].Y = P[i-1].Y + Sin(RandomAngle)

Related

how to calculate anti/clockwise angle in direction of lines?

I need to offset a curve, which by the simplest way is just shifting the points perpendicularly. I can access each point to calculate angle of each line along given path, for now I use atan2. Then I take those two angle and make average of it. It returns the shortest angle, not what I need in this case.
How can I calculate angle of each connection? Concerning that I am not interested in the shortest angle but the one that would create parallel offset curve.
Assuming 2D case...
So do a cross product of direction vectors of 2 neighboring lines the sign of z coordinate of the result will tell you if the lines are CW/CCW
So if you got 3 consequent control points on the polyline: p0,p1,p2 then:
d1 = p1-p0
d2 = p2-p1
if you use some 3D vector math then convert them to 3D by setting:
d1.z=0;
d2.z=0;
now compute 3D cross:
n = cross(d1,d2)
which returns vector perpendicular to both vectors of size equals to the area of quad (parallelogram) constructed with d1,d2 as base vectors. The direction (from the 2 possible) is determined by the winding rule of the p0,p1,p2 so inspecting z of the result is enough.
The n.x,n.y are not needed so you can compute directly without doing full cross product:
n.z=(d1.x*d2.y)-(d1.y*d2.x)
if (n.z>0) case1
if (n.z<0) case2
if the case1 is CW or CCW depends on your coordinate system properties (left/right handness). This approach is very commonly used in CG fur back face culling of polygons ...
if n.z is zero it means that your vectors/lines are either parallel or at lest one of them is zero.
I think these might interest you:
draw outline for some connected lines
How can I create an internal spiral for a polygon?
Also in 2D you do not need atan2 to get perpendicular vector... You can do instead this:
u = (x,y)
v = (-y,x)
w = (x,-y)
so u is any 2D vector and v,w are the 2 possible perpendicular vectors to u in 2D. they are the result of:
cross((x,y,0),(0,0,1))
cross((0,0,1),(x,y,0))

Calculate the number of circles that fit on the circumference of another circle

I'm looking for an algorithm (or pseudo code) that can calculate the maximum number of (smaller) circles with diameter "s" that can be squeezed into the circumference of another (larger) circle with radius "r" ...
Image: http://teasy.space/images/terracolony-squeezingcircles2.jpg
You can alternate between radius/diameter etc if you wish -- as these are the only 2 parameters (other than the center (large circle) coordinate) that i have, i.e. that are known ...
The outer circles may not overlap but can fit "snug" together ...
After various upgrades to my routine through the years, I'm currently using an algorithm that is not perfect (and it needs to be accurate or the galaxy breaks down lol)
which does a broad interpolation between small outside circle diameter and large inside circle circumference, to somewhat accurately plot the circle count in a polygon style fitting pattern, which causes problems (i.e. overlaps) when using larger outside circles ...
; try to fit a random number of circles
num_Circles = Rand( min,max )
; check if the number of circles exceed the maximum that can fit
If num_Circles * SmallCircle_Diameter > LargeCircle_Circumference
; adjust the amount accordingly
num_Circles = LargeCircle_Circumference / SmallCircle_Diameter
End If
Another assumption is that the size of the smaller outer circles never exceeds that of the larger inner circle ...
something less to worry about ;)
I'm using this algorithm for one of my projects called Terra Colony, based on Gravity Well, a 2D space/gravity realtime colonization simulation game with moons, planets, stars, black/white holes, etc
Image: http://teasy.space/images/terracolony-squeezingcircles1.jpg
This is an issue that has plagued this project for over a decade!
Hopefully you can point me in the right direction :D
I have previously done many experiments and wrote different programs to find a solution, and have traveled the internet looking for formulas and solutions which in the end are very close, but not close enough! :P
Thank you! <3
Teasy
P.S. I tried to add the tag "circumference" but it apparently requires "1500 reputation" (points i guess, maybe to prevent spam)
There is formula that establishes relation between radius of big circle R, radius of small circle r and number of (touching) small circles N
R = r / Sin(Pi/N)
So maximum number of small circles might be found as
Sin(Pi/N) = r / R
Pi / N = arcsin(r / R)
and finally
N = Pi / arcsin(r / R)
Example:
R=5
r=2.5
so
N = Pi / arcsin(1/2) =
Pi / (Pi/6) =
6
Given the diam. of the small circle 'd' and the number of them 'c'
then the dia. of the large circle 'D' is
D=d/sin(180/c)

Making a Bezier curve based on 3 points the line will intersect

A quadratic bezier curve needs these three points, but I do not have an ordered pair of p1. Instead, I have the ordered pair of points here
The middle point (P1) is the highest point of the parabola.
The parabola is equal in both sides
How do I get the 3 points from image 1 using the points from image 2?
Apply the knowledge explained in https://pomax.github.io/bezierinfo/#abc and you should be good to go. You'll need to decide which time value that "somewhere on the curve" point has, and then you can use the formula for the projection ratio to find the actual control point coordinate.
However, at t=0.5 the ratio is just "1:1" so things get even easier because your point projects onto the midpoint of the line that connects that first and last point, and the real control point is the same distance "above" your point as the point is above that line:
So you just compute the midpoint:
m =
x: (p1.x + p2.x) / 2
y: (p1.y + p2.y) / 2
and the x and y distance to the midpoint from the "p2 you have" point:
d =
x: (p2.x - m.x)
y: (p2.y - m.y)
and then the real p2 is simply that distance away from the "p2 you have":
real2 =
x: p2.x + d.x
y: p2.y + d.y
However, note that this only works for t=0.5: both that projected point on the start--end line and the distance ratios will be (possibly very) different for any other t value and you should use the formula that the Bezier primer talks about.
Also note that what you call "the peak" is in no way guaranteed to be at t=0.5... for example, have a look at this curve:
The point that is marked as belonging to t=0.5 is certainly not where you would say the "peak" of the curve is (in fact, that's closer to t=0.56), so if all you have is three points, you technically always have incomplete information and you're going to have to invent some rule for deciding how to fill in the missing bits. In this case "what t value do I consider my somewhere-on-the-curve point to be?".

What is the fastest way to find the center of an irregular convex polygon?

I'm interested in a fast way to calculate the rotation-independent center of a simple, convex, (non-intersecting) 2D polygon.
The example below (on the left) shows the mean center (sum of all points divided by the total), and the desired result on the right.
Some options I've already considered.
bound-box center (depends on rotation, and ignores points based on their relation to the axis).
Straight skeleton - too slow to calculate.
I've found a way which works reasonably well, (weight the points by the edge-lengths) - but this means a square-root call for every edge - which I'd like to avoid.(Will post as an answer, even though I'm not entirely satisfied with it).
Note, I'm aware of this questions similarity with:What is the fastest way to find the "visual" center of an irregularly shaped polygon?
However having to handle convex polygons increases the complexity of the problem significantly.
The points of the polygon can be weighted by their edge length which compensates for un-even point distribution.
This works for convex polygons too but in that case the center point isn't guaranteed to be inside the polygon.
Psudo-code:
def poly_center(poly):
sum_center = (0, 0)
sum_weight = 0.0
for point in poly:
weight = ((point - point.next).length +
(point - point.prev).length)
sum_center += point * weight
sum_weight += weight
return sum_center / sum_weight
Note, we can pre-calculate all edge lengths to halve the number of length calculations, or reuse the previous edge-length for half+1 length calculations. This is just written as an example to show the logic.
Including this answer for completeness since its the best method I've found so far.
There is no much better way than the accumulation of coordinates weighted by the edge length, which indeed takes N square roots.
If you accept an approximation, it is possible to skip some of the vertices by curve simplification, as follows:
decide of a deviation tolerance;
start from vertex 0 and jump to vertex M (say M=N/2);
check if the deviation along the polyline from 0 to M exceeds the tolerance (for this, compute the height of the triangle formed by the vertices 0, M/2, M);
if the deviation is exceeded, repeat recursively with 0, M/4, M/2 and M/2, 3M/4, M;
if the deviation is not exceeded, assume that the shape is straight between 0 and M.
continue until the end of the polygon.
Where the points are dense (like the left edge on your example), you should get some speedup.
I think its easiest to do something with the center of masses of the delaunay triangulation of the polygon points. i.e.
def _centroid_poly(poly):
T = spatial.Delaunay(poly).simplices
n = T.shape[0]
W = np.zeros(n)
C = 0
for m in range(n):
sp = poly[T[m,:],:]
W[m] = spatial.ConvexHull(sp).volume
C += W[m] +np.mean(sp, axis = 0)
return C / np.sum(W)
This works well for me!

How do I QUICKLY find the closest intersection in 2D between a ray and m polylines?

How do I find the closest intersection in 2D between a ray:
x = x0 + t*cos(a), y = y0 + t*sin(a)
and m polylines:
{(x1,y1), (x2,y2), ..., (xn,yn)}
QUICKLY?
I started by looping trough all linesegments and for each linesegment;
{(x1,y1),(x2,y2)} solving:
x1 + u*(x2-x1) = x0 + t*cos(a)
y1 + u*(y2-y1) = y0 + t*sin(a)
by Cramer's rule, and afterward sorting the intersections on distance, but that was slow :-(
BTW: the polylines happens to be monotonically increasing in x.
Coordinate system transformation
I suggest you first transform your setup to something with easier coordinates:
Take your point p = (x, y).
Move it by (-x0, -y0) so that the ray now starts at the center.
Rotate it by -a so that the ray now lies on the x axis.
So far the above operations have cost you four additions and four multiplications per point:
ca = cos(a) # computed only once
sa = sin(a) # likewise
x' = x - x0
y' = y - y0
x'' = x'*ca + y'*sa
y'' = y'*ca - x'*sa
Checking for intersections
Now you know that a segment of the polyline will only intersect the ray if the sign of its y'' value changes, i.e. y1'' * y2'' < 0. You could even postpone the computation of the x'' values until after this check. Furthermore, the segment will only intersect the ray if the intersection of the segment with the x axis occurs for x > 0, which can only happen if either value is greater than zero, i.e. x1'' > 0 or x2'' > 0. If both x'' are greater than zero, then you know there is an intersection.
The following paragraph is kind of optional, don't worry if you don't understand it, there is an alternative noted later on.
If one x'' is positive but the other is negative, then you have to check further. Suppose that the sign of y'' changed from negative to positive, i.e. y1'' < 0 < y2''. The line from p1'' to p2'' will intersect the x axis at x > 0 if and only if the triangle formed by p1'', p2'' and the origin is oriented counter-clockwise. You can determine the orientation of that triangle by examining the sign of the determinant x1''*y2'' - x2''*y1'', it will be positive for a counter-clockwise triangle. If the direction of the sign change is different, the orientation has to be different as well. So to take this together, you can check whether
(x1'' * y2'' - x2'' * y1'') * y2'' > 0
If that is the case, then you have an intersection. Notice that there were no costly divisions involved so far.
Computing intersections
As you want to not only decide whether an intersection exists, but actually find a specific one, you now have to compute that intersection. Let's call it p3. It must satisfy the equations
(x2'' - x3'')/(y2'' - y3'') = (x1'' - x3'')/(y1'' - y3'') and
y3'' = 0
which results in
x3'' = (x1'' * y1'' - x2'' * y2'')/(y1'' - y2'')
Instead of the triangle orientation check from the previous paragraph, you could always compute this x3'' value and discard any results where it turns out to be negative. Less code, but more divisions. Benchmark if in doubt about performance.
To find the point closest to the origin of the ray, you take the result with minimal x3'' value, which you can then transform back into its original position:
x3 = x3''*ca + x0
y3 = x3''*sa + y0
There you are.
Note that all of the above assumed that all numbers were either positive or negative. If you have zeros, it depends on the exact interpretation of what you actually want to compute, how you want to handle these border cases.
To avoid checking intersection with all segments, some space partition is needed, like Quadtree, BSP tree. With space partition it is needed to check ray intersection with space partitions.
In this case, since points are sorted by x-coordinate, it is possible to make space partition with boxes (min x, min y)-(max x, max y) for parts of polyline. Root box is min-max of all points, and it is split in 2 boxes for first and second part of a polyline. Number of segments in parts is same or one box has one more segment. This box splitting is done recursively until only one segment is in a box.
To check ray intersection start with root box and check is it intersected with a ray, if it is than check 2 sub-boxes for an intersection and first test closer sub-box then farther sub-box.
Checking ray-box intersection is checking if ray is crossing axis aligned line between 2 positions. That is done for 4 box boundaries.

Resources