Generating points uniformly on a sphere - algorithm

I'm interested in generating points that are 'uniformly' (and non-randomly) distributed around a sphere, much like the dimples of a golf ball or the vertices of the hexagons on a soccer ball. Are there well defined algorithms to do this?
Note: I know that the points are not really 'uniformly' distributed on a sphere, but they are distributed in a way that the distribution of points looks the same from any direction that looks straight at any of the points - this is what I am interested in.

Subdividing an octahedron and normalizing the vertices afterwards gives very good results. Look here for more details. Paul Bourke has a lot of interesting stuff.
Here's some psuedo C++ code I wrote up in five minutes now:
/* Assume 'data' initially holds vertices for eight triangles (an octahedron) */
void GenerateSphere(float radius, std::vector<Vector3f>& data, int accum=10)
{
assert( !(data.size() % 3) );
std::vector<Vector3f> newData;
for(int i=0; i<data.size(); i+=3){
/* Tesselate each triangle into three new ones */
Vector3f centerPoint = (data[i] + data[i+1] + data[i+2]) / 3.0f;
/* triangle 1*/
newData.push_back(data[i+0]);
newData.push_back(data[i+1]);
newData.push_back(centerPoint);
/* triangle 2*/
newData.push_back(data[i+1]);
newData.push_back(data[i+2]);
newData.push_back(centerPoint);
/* triangle 3*/
newData.push_back(centerPoint);
newData.push_back(data[i+2]);
newData.push_back(data[i+0]);
}
data = newData;
if(!accum){
/* We're done. Normalize the vertices,
multiply by the radius and return. */
for(int i=0; i<data.size(); ++i){
data[i].normalize();
data[i] *= radius;
}
} else {
/* Decrease recursion counter and iterate again */
GenerateSphere(radius, data, accum-1);
}
return;
}
This code will work with any polyhedron made of counter-clockwise triangles, but octahedrons are best.

Choose u,v randomly from [0,1].
2πu is longitude.
asin(2v-1) is latitude.
Only two random variables, and no rejections.
By the way, my link collection has a new address: http://bendwavy.org/sphere.htm
And I've copied it over to http://cgafaq.info/wiki/Evenly_distributed_points_on_sphere

While this article talks about randomly picking points on a sphere, it is also about drawing points from a uniform distribution while at the same time taking the sphere characteristic into consideration. I guess it's still a decent read for your question:
http://mathworld.wolfram.com/SpherePointPicking.html

depending on your needs http://iquilezles.untergrund.net/www/articles/patchedsphere/patchedsphere.htm
may work well too. not exactly uniform, but very fast to compute.

Here's a simple way to do it.
Randomly, sample from the unit cube, [0, 1]^3
Test for inclusion in the sphere. Reject if the sampled point is not in the sphere of diameter 1 that is contained in the unit cube, and go to step 1.
Normalize the point to be on the surface of the sphere, by projecting the point outward from the center of the sphere.
This will typically succeed after a few samples. If you want, you can also reject samples that are near the center of the sphere to minimize rounding errors and help make the distribution closer to uniform.

if you're okay with having only certain allowable numbers of vertices, then the subdivision methods above are definitely the way to go. if you want an arbitrarily-specified number of vertices, then i recommend:
first, distribute points randomly and uniformly over the sphere.
i talk at length about doing this at http://elenzil.com/progs/randompoints .
i believe my method is at least as performant as that at worlfram.
second, "relax" the distribution by treating the points as a particle system where each particle repels every other particle. the difficulty here is making sure the system doesn't become unstable, and deciding when to stop. i have an example of this here: http://elenzil.com/progs/separate unfortunately these were the days before i included source code with my projects, so that code is lost.

I tried once the following algorithm:
start with a regular tetrahedron with the submits on the sphere.
pick one of the triangles with the biggest surface (initially it will be any of the 4 sides)
replace selected face with a 3 sided pyramid where the 4th point is the elevation of the face center to the sphere surface.
repeat until enough points have been created.
This works as long as precision does not ruin uniformity.
The resulting points form figures akin to a geode.
You don't need to compute any surface, since each new triangle is no greater than all previous ones. Simply handle them in FIFO order.

Related

how to compute the shortest distance from a point to triangle using tesselated data

i have to solve a distance problem and i´m getting pretty upset because i don´t know how to do it despite having tried nearly everything that i´ve found on the web... here´s my problem:
i work in the automotive industry and we use tessellated data (like STL, in my case the JT-Format). I have a part that needs to be welded. and i have the coordinates of the weldpoint. to ensure that the weldpoint is located correctly i want to calculate if the weldpoint hits the part or, in other words, i want to check if the weldpoint collides with the part. if yes, then the part can be welded. otherwise the weldpoint would be in the air and it couldnt be welded. therefor i want to calculate the distance between the part (which is basically a set of triangles or polygons in the mentioned format) and the point. if the distance to one of the triangles is less then the also given radius of the weldpoint, then there must be a collision and thus the weldpoint is located correctly and can be welded.
a how to, pseudo-code or whatever that could be useful would be very appreciated. i´m coding in c++ using the JTOpen Toolkit. Please note that the point hasn´t necessarily have to lie within the triangle. Maybe an example could help you and me to understand the problems/answers (no collision in the following example):
let v1, v2, v3 be the vertices of a triangle and px, py, pz the coordinates of the weldpoint (radius 1.8). I also get normals (n1, n2, n3) to every vertex but i dont know what to to with them...
v1x = -273.439
v1y = -787.775
v1z = 854.273
v2x = -274.247
v2y = -788.085
v2z = 855.244
v3x = -272.077
v3y = -787.864
v3z = 855.377
px = 140.99
py = -787.78
pz = 458.93
n1x = -0.113447
n1y = 0.97007
n1z = 0.214693
n2x = -0.113423
n2y = 0.970069
n2z = 0.214712
n3x = -0.110158
n3y = 0.969844
n3z = 0.217413
thank you in advance!
The locus of the points at the same distance of a triangle is a complex surface made of
two triangles parallel to the original one, at the given distance;
three half cylindres corresponding to points at equal distances of the edges;
the spheres with points at equal distances of the vertices.
If you look facing the triangle, you will observe that these surfaces are split by
the three triangle sides,
the six normals to the sides at the vertices.
Hence to find the distance of a given point, you need to project it orthogonally to the plane of the triangle and find its location among 7 regions delimited by half-lines and segments. Using an appropriate spatial rotation, the problem can be solved in 2D. Then knowing the region, you will use either the distance to the plane, to an edge or to a vertex.
Note that in the case of a tessellation, several triangles have to be considered. If there are many of them, acceleration systems will be needed. This is a broad and a little technical topic.

Snapping vector to a point from a grid on a sphere (icosahedron)

here is a problem that will turn your brain inside out, I'm trying to deal with it for a quite some time already.
Suppose you have sphere located in the origin of a 3d space. The sphere is segmented into a grid of equidistant points. The procedure that forms grid isn't that important but what seems simple to me is to use regular 3d computer graphics sphere generation procedure (The algorithm that forms the sphere described in the picture below)
Now, after I have such sphere (i.e. icosahedron of some degree) I need a computationally trivial procedure that will be capable to snap (an angle) of a random unit vector to it's closest icosahedron edge points. Also it is acceptable if the vector will be snapped to a center point of triangle that the vector is intersecting.
I would like to emphasise that it is important that the procedure should be computationally trivial. This means that procedures that actually create a sphere in memory and then involve a search among every triangle in sphere is not a good idea because such search will require access to global heap and ram which is slow because I need to perform this procedure millions of times on a low end mobile hardware.
The procedure should yield it's result through a set of mathematical equations based only on two values, the vector and degree of icosahedron (i.e. sphere)
Any thoughts? Thank you in advance!
============
Edit
One afterthought that just came to my mind, it seems that within diagram below step 3 (i.e. Project each new vertex to the unit sphere) is not important at all, because after bisection, projection of every vertex to a sphere would preserve all angular characteristics of a bisected shape that we are trying to snap to. So the task simplifies to identifying a bisected sub triangle coordinates that are penetrated by vector.
Make a table with 20 entries of top-level icosahedron faces coordinates - for example, build them from wiki coordinate set)
The vertices of an icosahedron centered at the origin with an
edge-length of 2 and a circumscribed sphere radius of 2 sin (2π/5) are
described by circular permutations of:
V[] = (0, ±1, ±ϕ)
where ϕ = (1 + √5)/2
is the golden ratio (also written τ).
and calculate corresponding central vectors C[] (sum of three vectors for vertices of every face).
Find the closest central vector using maximum of dot product (DP) of your vector P and all C[]. Perhaps, it is possible to reduce number of checks accounting for P components (for example if dot product of P and some V[i] is negative, there is no sense to consider faces being neighbors of V[i]). Don't sure that this elimination takes less time than direct full comparison of DP's with centers.
When big triangle face is determined, project P onto the plane of that face and get coordinates of P' in u-v (decompose AP' by AB and AC, where A,B,C are face vertices).
Multiply u,v by 2^N (degree of subdivision).
u' = u * 2^N
v' = v * 2^N
iu = Floor(u')
iv = Floor(v')
fu = Frac(u')
fv = Frac(v')
Integer part of u' is "row" of small triangle, integer part of v' is "column". Fractional parts are trilinear coordinates inside small triangle face, so we can choose the smallest value of fu, fv, 1-fu-fv to get the closest vertice. Calculate this closest vertex and normalize vector if needed.
It's not equidistant, you can see if you study this version:
It's a problem of geodesic dome frequency and some people have spent time researching all known methods to do that geometry: http://geo-dome.co.uk/article.asp?uname=domefreq, see that guy is a self labelled geodesizer :)
One page told me that the progression goes like this: 2 + 10·4N (12,42,162...)
You can simplify it down to a simple flat fractal triangle, where every triangle devides into 4 smaller triangles, and every time the subdivision is rotated 12 times around a sphere.
Logically, it is only one triangle rotated 12 times, and if you solve the code on that side, then you have the lowest computation version of the geodesic spheres.
If you don't want to keep the 12 sides as a series of arrays, and you want a lower memory version, then you can read about midpoint subdivision code, there's a lot of versions of midpoint subdivision.
I may have completely missed something. just that there isn't a true equidistant geodesic dome, because a triangle doesn't map to a sphere, only for icos.

create a concave polygon from image using N points

i am looking for a algorithm that will generate a concave polygon (with N points where N > 3 - user enters this value) from a image.
My idea for the algorithm:
// Every pixel in image is checked and a minimal orientated bounding box is generated (transparent pixels are ignored)
boundingBox = createImageBoundingBox(image);
curpoints = 4, A = 0, B = 1, tmppoints = curpoints;
while(curpoints < maxNumberOfPoints)
{
add a new point between point A and point B (A and B are points from the boundingBox)
reposition points so that it will contain the minimal surface
A++; B++;
curpoints++;
if(A == tmppoints)
{ A = 0; B = 1; tmppoints=curpoints; }
}
The problem im facing is i dont know how to optimally reposition points. Can this be done any other (better/faster way). Would appreciate any thoughts.
Thanks
EDIT:
The image has to be at least 10x10. I need the N points parameter so the user can regulate how many points are going to be used (for optimization). An alternative would be to have a factor (0-1) which tells how much detailed (how many points) you want the polygon to have (0 being 4 points, > 0 5 or more points). But not sure how to implement it.
You can use a delaunay triangulation and get the average edge lenght. Then try to remove edges that are longer then the average. The concept is from the alpha shapes.
Concave hull may be built with alpha shapes. CGAL link.
1.) Select a point in the middle of the square image.
2.) Jitter this point N times randomly from the center to generate N new points.
3.) Sort these points based on maximum angle from the center point
4.) Use your four points in your bounding box and your midpoint(s) in sorted ascending angle order to create the ordered point list of your concave polygon.
I am not sure if I understand your 'minimal surface' step above, but I believe this algorithm will work for taking a cut out of image to generate a concave polygon. I think this is faster than your above, but I am not sure because I don't understand that step fully.
This will always generate a concave polygon with the same bounds as your original image. If you don't want this, you could add a step 0.) that jitters your bounding box, and then changes your midpoint jitter based on this. Both of these ideas will result in a bounding quadrilateral with a n-sized point chunk taken out, I think.
This requires n > 4 (collapse two of you bounding box points into one if you want this to require n > 3, like you said you want.)

Breakpoint Convergence in Fortune's Algorithm

I am implementing Fortune's sweepline algorithm for computing Voronoi diagrams. My primary reference is "Computational Geometry: Algorithms and Applications" by de Berg et al., and while their coverage of the topic is very clear, they pass over several small but important details that I have been having trouble working out myself. I've searched the web for help, but other websites either give an even higher overview than the textbook, or give the exact same pseudocode provided by the book.
I need a way to determine whether a pair of breakpoints determined by a triple of arcs on the beach line converges or diverges, in order to detect upcoming circle events. It seems that to make a decision I would need knowledge about the shape of the Voronoi cell edges that the breakpoints trace out as Fortune's algorithm progresses. For example, if I could find the slope of the edge traced by a breakpoint I could calculate where the two lines formed by the breakpoints and their respective slopes intersect, and decide whether they converge based on that result. However, I have no idea how to get information on the slopes, only the current position of the breakpoints.
The only information I have to work with is the x,y location of the three sites and the current y-coordinate of the sweepline (I'm using a horizontal sweepline).
Actually, I do have one idea for determining convergence. Given two sites, the breakpoint between the two sections of the beachline they define is governed only by the current position of the sweep line. I thought about recording the position of the two breakpoints, temporarily advancing the sweep line a small amount, and recording their new positions. Because edges in a normal Voronoi diagram do not curve, if the distance between the new pair of breakpoints is less than the distance between the old pair, then the breakpoints converge; otherwise, they diverge. But this seems both dangerous (I have no idea if it always works) and ugly. Surely there must be a better way.
Any ideas would be appreciated, and pseudocode (in a C#-like syntax if possible) especially so. Also I am aware that there are computational geometry libraries that I could use to get Voronoi diagrams, but this is a personal learning exercise, so I want to implement all parts of the algorithm myself.
So this is rather embarassing, but after sleeping on the problem the answer seems obvious. I'm writing this to hopefully help students in the future with the same question as me.
The Voronoi edge between two sites perpendicularly bisects the (imaginary) line segment connecting the sites. You could derive the slope of the edge by taking the perpendicular of the slope of the connecting line segment, and then performing a line intersection test on the two edges, but there is an even easier way.
As long as three sites are not collinear, then the edges that perpendicularly bisect the segments between the sites are also tangent to the circle whose edge contains all three sites. Therefore the breakpoints defined by a triple of Voronoi sites converge if the center of the circle defined by the three sites is in front of the middle site, where "in front" and "behind" depend on the coordinate system and sweepline alignment you have chosen.
In my case, I have a horizontal sweepline that I am moving from minimum y to maximum y, so the breakpoints converge if the y-coordinate of the center of the circle is greater than the y-coordinate of the middle site, and diverge otherwise.
Edit: Kristian D'Amato rightfully points out that the algorithm above misses some convergence cases. The final algorithm I ended up using is below. Of course, I'm not confident that its 100% correct, but it seems to work for all the cases I tried it out on.
Given left, middle, right sites
if they are collinear, return false
center = ComputeCircleCenterDefinedBy3Points(left, middle, right)
return IsRightOfLine(left, middle, center) && IsRightOfLine(middle, right, center)
IsRightOfLine(start, end, point)
((end.X - start.X) * (point.Y - start.Y) - (end.Y - start.Y) * (point.X - start.X)) <= 0
Welcome Drake. I implemented it by checking whether the breakpoints physically converge on the circle center in a 'fictitious' increment of the sweepline position. This actually complicates itself a bit because in certain cases the circle center can be almost or precisely at the sweepline position, so the sweepline increment needs to be proportional to the difference between the current sweepline position and the circle center generated as you recommend.
Say:
1. currentSweeplineY = 1.0f; circleCenterY = 0.5f (and we are moving downwards, i.e. in the decreasing y direction).
2. Set sweepYIncrement = (circleCenterY - currentSweepLineY) / 10.0f (the 10.0f divisor is arbitrarily chosen).
3. Check new breakpoint positions at new sweepline position.
4. Check distance to circle center.
5. If both distances are less than current distances, the breakpoints converge.
I know this is probably very expensive, since you have to calculate the breakpoint positions multiple times, but I'm confident it takes care of all possible cases.
Anyway, I'm finding serious issues with floating point precision error elsewhere in the algorithm. Definitely not as straightforward as I thought initially.
If the sites are ordered clockwise around the center of the circle, the arc is converging. If they are ordered counterclockwise around the center of the circle, the arc is diverging. (or vice versa, depending on your implementation). Testing for cw or ccw falls out of the code you use to find the center of the circle.
Here's a snippet of C# code for computing the circumcenter d of points a,b,c:
Vector2 ba = b - a;
Vector2 ca = c - a;
float baLength = (ba.x * ba.x) + (ba.y * ba.y);
float caLength = (ca.x * ca.x) + (ca.y * ca.y);
float denominator = 2f * (ba.x * ca.y - ba.y * ca.x);
if (denominator <= 0f ) { // Equals 0 for colinear points. Less than zero if points are ccw and arc is diverging.
return false; // Don't use this circle event!
};
d.x = a.x + (ca.y * baLength - ba.y * caLength) / denominator ;
d.y = a.y + (ba.x * caLength - ca.x * baLength) / denominator ;

Arduino convex hull algorithm

I am working on a project using an Arduino that needs to calculate the area of a polygon made up of many points. I use surveyor's theorem,
But the points are in random order, not (counter)clockwise. Some make lines that cross, and they make polygons like a bow-tie or hourglass, which don't work for the surveyor's theorem, so I need to sort them in (counter)clockwise order. what is the easiest way to do this?
You don't need to find the convex hull. Just use the area formula from a bunch of points ordered counterclockwise:
http://en.wikipedia.org/wiki/Polygon#Area_and_centroid
float totalArea = 0.0;
for(i=0; i<N; i++) {
float parallelogramArea = (point[i].x*point[i+1].y - point[i+1].x*point[i].y)
float triangleArea = parallelogramArea / 2.0;
totalArea += triangleArea;
}
// or divide by 2 out here for efficiency
The area formula comes from taking each edge AB, and calculating the (signed) area between the edge and the origin (triangle ABO) by taking the cross-product (which gives you the area of a parallelogram) and cutting it in half (factor of 1/2). As one wraps around the polygon, these positive and negative triangles will overlap, and the area between the origin and the polygon will be cancelled out and sum to 0, while only the area inside remains. This is why the formula is called the Surveyor's Formula, since the "surveyor" is at the origin; if going counterclockwise, positive area is added when going left->right and negative area is added when going right->left, from the perspective of the origin.
The mathematical formula is given below, but does not provide the intuition behind it (as given above):
edit (after question has been changed)
There is absolutely no way to "get their order" without additional assumptions, e.g. "the polygon is convex".
If the polygon is concave, it becomes nearly impossible in the general case without lots of extra assumptions (proof: consider a point which lies within the convex hull, but whose neighbors do not; there are many possible valid polygons you can construct using that point, its neighbors, and their neighbors).
If the polygon is convex, all you need to do is sort by the angle from some arbitrary point inside the polygon (e.g. centroid of three arbitrary points).
You could find the center of gravity (cx,cy) of the points and then calculate the angles of the points relative to (cx,cy).
angle[i] = atan2(y[i]-cy, x[i]-cx) ;
Then sort the points by angle.
Just beware that a random set of points does not describe a single unique polygon. So this method will just give you one of the possible polygons, and not necessarily the polygon you would have obtained if you had manually connected the dots.

Resources