I have a bunch of spheres with different radius scattered all over the place in a 3D system.
What would be the fastest way to determine what sphere a point is inside, and if it is inside more than one - also the closest sphere based on the sphere's center.
The bruteforce method is to simply loop over all spheres, calculate the distance to the point, check if that distance is smaller than the sphere's radius and then find the sphere with the shortest disrance.
However, I got a couple million points to check (with about 100k spheres), so this would be incredibly slow.
Another idea of mine would be to build some kind of BVH Acceleration structure and save for each cell what sphere is the closest. However, there are also cases where one cell could be overlapped by two or more spheres etc. So a lot of edge-cases to consider.
And after all, the computation of the BVH tree should not be slower than the bruteforce.
Any ideas?
I ended up doing it with the brute force method on the GPU via OpenCL - that's super fast :)
Maybe a Sweep and Prune¹-esque approach could work here?
Handwavy algorithm (2D case):
Create two arrays Ax and Ay.
Pick one circle out of n circles and project into onto the x-axis, i.e store the x-component of the circles center plusminus the radius in Ax. Project the circle onto the y-axis as well.
Repeat step 2 for all remaining circles.
Store the components for each point in Ax and Ay as well.
Sort Ax and Ay
From here on, a point P can only be within a sphere S iff it is contained within all three intervals of S.
Now, it's possible to determine for each point if it is contained by a sphere: Iterate over Ax and increment a counter k each time you "enter" an interval and decrement k when you "exit" an interval. If the counter is k when you sweep into a point, then the point is contained by a set I of k intervals. Check if the point is contained by any corresponding interval of I in Ay².
Again, sortedness of Ax and Ay should be of help when finding what sphere was closest to a point.
I'm confident that this approach can be (much) improved upon, and in practice the parallelized brute-force could be faster still.
Handwavy algorithm (3D case): Analogous to the 2D case.
¹. http://www.cs.jhu.edu/~cohen/Publications/icollide.pdf
². I obviously omit lots of d̶e̶t̶a̶i̶l̶s̶ ̶I̶ ̶h̶a̶v̶e̶ ̶y̶e̶t̶ ̶t̶o̶ ̶f̶i̶g̶u̶r̶e̶ ̶o̶u̶t boring bookkeeping details.
Related
I have a 3D mesh consisting of triangle polygons. My mesh can be either oriented left or right:
I'm looking for a method to detect mesh direction: right vs left.
So far I tried to use mesh centroid:
Compare centroid to bounding-box (b-box) center
See if centroid is located left of b-box center
See if centroid is located right of b-box center
But the problem is that the centroid and b-box center don't have a reliable difference in most cases.
I wonder what is a quick algorithm to detect my mesh direction.
Update
An idea proposed by #collapsar is ordering Convex Hull points in clockwise order and investigating the longest edge:
UPDATE
Another approach as suggested by #YvesDaoust is to investigate two specific regions of the mesh:
Count the vertices in two predefined regions of the bounding box. This is a fairly simple O(N) procedure.
Unless your dataset is sorted in some way, you can't be faster than O(N). But if the point density allows it, you can subsample by taking, say, every tenth point while applying the procedure.
You can as well keep your idea of the centroid, but applying it also in a subpart.
The efficiency of an algorithm to solve your problem will depend on the data structures that represent your mesh. You might need to be more specific about them in order to obtain a sufficiently performant procedure.
The algorithms are presented in an informal way. For a more rigorous analysis, math.stackexchange might be a more suitable place to ask (or another contributor is more adept to answer ...).
The algorithms are heuristic by nature. Proposals 1 and 3 will work fine for meshes whose local boundary's curvature is mostly convex locally (skipping a rigorous mathematical definition here). Proposal 2 should be less dependent on the mesh shape (and can be easily tuned to cater for ill-behaved shapes).
Proposal 1 (Convex Hull, 2D)
Let M be the set of mesh points, projected onto a 'suitable' plane as suggested by the graphics you supplied.
Compute the convex hull CH(M) of M.
Order the n points of CH(M) in clockwise order relative to any point inside CH(M) to obtain a point sequence seq(P) = (p_0, ..., p_(n-1)), with p_0 being an arbitrary element of CH(M). Note that this is usually a by-product of the convex hull computation.
Find the longest edge of the convex polygon implied by CH(M).
Specifically, find k, such that the distance d(p_k, p_((k+1) mod n)) is maximal among all d(p_i, p_((i+1) mod n)); 0 <= i < n;
Consider the vector (p_k, p_((k+1) mod n)).
If the y coordinate of its head is greater than that of its tail (ie. its projection onto the line ((0,0), (0,1)) is oriented upwards) then your mesh opens to the left, otherwise to the right.
Step 3 exploits the condition that the mesh boundary be mostly locally convex. Thus the convex hull polygon sides are basically short, with the exception of the side that spans the opening of the mesh.
Proposal 2 (bisector sampling, 2D)
Order the mesh points by their x coordinates int a sequence seq(M).
split seq(M) into 2 halves, let seq_left(M), seq_right(M) denote the partition elements.
Repeat the following steps for both point sets.
3.1. Select randomly 2 points p_0, p_1 from the point set.
3.2. Find the bisector p_01 of the line segment (p_0, p_1).
3.3. Test whether p_01 lies within the mesh.
3.4. Keep a count on failed tests.
Statistically, the mesh point subset that 'contains' the opening will produce more failures for the same given number of tests run on each partition. Alternative test criteria will work as well, eg. recording the average distance d(p_0, p_1) or the average length of (p_0, p_1) portions outside the mesh (both higher on the mesh point subset with the opening). Cut off repetition of step 3 if the difference of test results between both halves is 'sufficiently pronounced'. For ill-behaved shapes, increase the number of repetitions.
Proposal 3 (Convex Hull, 3D)
For the sake of completeness only, as your problem description suggests that the analysis effectively takes place in 2D.
Similar to Proposal 1, the computations can be performed in 3D. The convex hull of the mesh points then implies a convex polyhedron whose faces should be ordered by area. Select the face with the maximum area and compute its outward-pointing normal which indicates the direction of the opening from the perspective of the b-box center.
The computation gets more complicated if there is much variation in the side lengths of minimal bounding box of the mesh points, ie. if there is a plane in which most of the variation of mesh point coordinates occurs. In the graphics you've supplied that would be the plane in which the mesh points are rendered assuming that their coordinates do not vary much along the axis perpendicular to the plane.
The solution is to identify such a plane and project the mesh points onto it, then resort to proposal 1.
I'm using the centroid of polygons to attach a marker in a map application. This works definitely fine for convex polygons and quite good for many concave polygons.
However, some polygons (banana, donut) obviously don't produce the desired result: The centroid is in these cases outside the polygons area.
Does anybody know a better approach to find a suitable point within any polygons area (which may contain holes!) to attach a marker?
One approach would be to generate and refine a skeleton of the polygon, then use the midpoint of the skeleton to place your marker (and if it's text, to orient the text correctly). This works well for most shapes, including ones with holes, and banana-shaped or tadpole-shaped crescents.
The CGAL library has a 2D Straight Skeleton and Polygon Offsetting module, or you could use PostGIS, for example.
To rephrase comment of ChristopheRoussy we may look for the largest circle inside of the polygon.
The largest circle is the one which cannot grow anymore because it touches three vertices or edges (if it touches only two, it can become bigger or just moved until it touches third).
So if you have few vertices, you can just enumerate all possible triples of vertices/edges, find for each one a circle and then select the largest one.
But it will require creating four functions:
Circle(vertex,vertex,vertex)
Circle(vertex,vertex,edge)
Circle(vertex,edge,edge)
Circle(edge,edge,edge)
All of them are possible, but may require some effort.
Find the extreme ordinates and draw an horizontal line in the middle. It is guaranteed to cross the polygon.
Find the intersection with the sides and sort them by increasing abscissa. Pick a point in the middle of two intersections.
This is an O(N + K Log K) process where K is the number of intersections (usually a very small even number). Pretty straightforward to write.
To increase the chances of a nice placement, you can try three horizontals instead of one an pick the longest intersection segment.
I have no idea how to solve this for any possible shape (and not doing heavy computation), but maybe for simpler shapes like the ones you have shown:
https://en.wikipedia.org/wiki/Force-directed_graph_drawing
Heuristic: This could converge to a reasonable approximation after a while
transform shape border into many points (more = more precise)
start out with many random points inside the polygon
push them until they are furthest away from border points, or just compute distance ... (can be done in parallel)
take best point
Another way could be to use multiple algorithms depending on the nature of the shape (like another one for donuts ...). Also perhaps relying on measuring 'fattest' sections first ?
IMHO would ask this on a math forum.
Similar: Calculate Centroid WITHIN / INSIDE a SpatialPolygon
Similar: How to find two most distant points?
To get a point for a marker I would use Yves Daoust's method.
To get a point that is reliably "within any polygon with holes" I would split polygon into triangles with a reliable library (e.g. OpenGL's GLUtessellator), and then get centroid of triangle with largest area.
If I had time for developing and testing, and I wanted good performance, then I would use a hybrid method: First use Yves Daoust's method to get some candidate points and then test candidates to see if they are within polygon. If all candidates fail, then fall back to slower reliable method (e.g. GLUtesselator).
for (int i = 0; i < n; /*++i*/) {
p = RandomPointInsideConvexHull();
if (IsInsidePolygon(p)) {
++i;
d = DistanceToClosestEdge(p);
if (d > bestD) {
bestP = p;
}
}
}
After running this loop you will approximate solution by bestP. n is parameter to choose. If you want more accurate result you can restart search, but now instead of picking a point inside polygon's convex hull you can pick one in the neighborhood of bestP, say not farther than bestD / 5 (this time you don't need to check if random point is inside polygon).
I am trying to create an algorithm for 'fleeing' and would like to first find points which are 'safe'. That is to say, points where they are relatively distant from other points.
This is 2D (not that it matters much) and occurs within a fixed sized circle.
I'm guessing the sum of the squared distances would produce a good starting equation, whereby the highest score is the furthest away.
As for picking the points, I do not think it would be possible to solve for X,Y but approximation is sufficient.
I did some reading and determined that in order to cover the area of a circle, you would need 7 half-sized circles (with centers forming a hex, and a seventh at the center)
I could iterate through these, all of which are within the circle to begin with. As I choose the best scoring sphere, I could continue to divide them into 7 spheres. Of course, excluding any points which fall outside the original circle.
I could then iterate to a desired precision or a desired level.
To expand on the approach, the assumption is that it takes time to arrive at a location and while the location may be safe, the trip in between may not. How should I incorporate the distance in the equation so that I arrive at a good solution.
I suppose I could square the distance to the new point and multiply it by the score, and iterate from there. It would strongly favor a local spot, but I imagine that is a good behavior. It would try to resolve a safe spot close by and then upon re-calculating it could find 'outs' and continue to sneak to safety.
Any thoughts on this, or has this problem been done before? I wasn't able to find this problem specifically when I looked.
EDIT:
I've brought in the C# implementation of Fortune's Algorithm, and also added a few points around my points to create a pseudo circular constraint, as I don't understand the algorithm well enough to adjust it manually.
I realize now that the blue lines create a path between nodes. I can use the length of these and the distance between the surrounding points to compute a path (time to traverse and danger) and weigh that against the safety (the empty circle it is trying to get to) to determine what is the best course of action. By playing with how these interact, I can eliminate most of the work I would have had to do, simply by using the voronoi. Also my spawning algorithm will use this now, to determine the LEC and spawn at that spot.
You can take the convex hull of your set of locations - the vertices of the convex hull will give you the set of "most distant" points. Next, take the centroid of the points you're fleeing from, then determine which vertex of the convex hull is the most distant from the centroid. You may be able to speed this up by, for example, dividing the playing field into quadrants - you only need to test the vertices that are in the furthermost quadrant (e.g., if the centroid is in the positive-x positive-y quadrant, then you only need to check the vertices in the negative-x negative-y quadrant); if the playing field is an irregular shape then this may not be an option.
As an alternative to fleeing to the most distant point, if you have a starting point that you're fleeing from (e.g. the points you're fleeing from are enemies, and the player character is currently at point X which denotes its starting point), then rather than have the player flee to the most distant point you can instead have the player follow the trajectory that most quickly takes them from the centroid of the enemies - draw a ray from the enemies' centroid through the player's location, and that ray gives you the direction that the player should flee.
If the player character is surrounded then both of these algorithms will give nonsense results, but in that case the player character doesn't really have any viable options anyway.
It is simple to fill rectangle: simply make some grid. But if polygon is unconditioned the task becomes not so trivial.
Probably "regularly" can be formulated as distance between each other point would be: R ± alpha. But I'm not sure about this.
Maybe there is some known algorithm to achieve this.
Added:
I need to generate net, where no large holes, and no big gathering of the points.
Have you though about using a force-directed layout of the points?
Scatter a number of points randomly over the bounding box of your polygon, then repeatedly apply two simple rules to adjust their location:
If a point is outside of the polygon, move it the minimum possible distance so that it lies within, i.e.: to the closest point on the polygon edge.
Points repel each other with a force inversely proportional to the distance between them, i.e.: for every point, consider every other point and compute a repulsion vector that will move the two points directly apart. The vector should be large for proximate points and small for distant points. Sum the vectors and add to the point's position.
After a number of iterations the points should settle into a steady state with an even distribution over the polygon area. How quickly this state is achieved depends on the geometry of the polygon and how you've scaled the repulsive forces between the points.
You can compute a Constrained Delaunay triangulation of the polygon and use a Delaunay refinement algorithm (search with this keyword).
I have recently implemented refinement
in the Fade2D library, http://www.geom.at/fade2d/html/. It takes an
arbitrary polygon without selfintersections as well as an upper bound on the radius of the circumcircle of each resulting triangle. This feature is not contained in the current release 1.02 yet, but I can compile the current development version for Linux or Win64 if you want to try that.
Just wanted to know what is the best approach (in terms of speed and accuracy) to determine the points of intersection on N spheres (it was asked for two spheres here); wanted to know what would be the best language to do this. More detailed explanation about what I want to do is here.
As near as I can tell, you are asking for the intersection loci of each pair of N 3D spheres.
Counting symmetry, there are N * (N-1) / 2 pairs.
So take each pair.
If the distance between centers is greater than the sum of their radii, there is no intersection.
(Edit: Or, as #Ben points out, if the distance is less than the difference of radii, there is also no intersection.)
If it is equal, the intersection is a single point, easily found on the line segment between centers.
If it is less, the locus is a circle, not a point.
To find the center of that circle and its radius, you're going to need to take a plane slice through the two spheres.
That reduces the problem to finding the intersection of two circles.
For that you need the Law of Cosines.
Elaborated: Look at that Wikipedia diagram. a and b are the radii of the two spheres, and c is the distance between centers.
Use the second-to-last equation and solve for cos(alpha).
From that you can easily get sin(alpha).
Then b sin(alpha) is the radius of the circle,
and b cos(alpha) is the distance to its center.
(Note - this doesn't call any trig functions, only sqrt.)
Once you know the center and radius of the circle of intersection, the circle itself is just in a plane normal to the line segment connecting the sphere centers.
Beyond that, I'm not really sure what you want.
If i get you right, you want all intersections of at least two spheres from a group of N spheres, right?
If so, this is acually not an easy problem for high performance computing, at least not if you need an accurate solution.
This problem is also solved when calculating the "Reduced Surface" of molecules:
http://www.ncbi.nlm.nih.gov/pubmed/8906967
There are several publications on how to efficiently calculate these points and circles, but it is not an easy task.
I believe there was a publication to calculating these values with CUDA, but I don't remember the details. Google (Scholar) should be able to help you in this direction.
However, depending on what you want to achieve, there can be easier solutions.
So, perhaps you could detail your question?