I am trying to determine the distance from a point to a polygon in 2D space. The point can be inside or outside the polygon; The polygon can be convex or concave.
If the point is within the polygon or outside the polygon with a distance smaller than a user-defined constant d, the procedure should return True; False otherwise.
I have found a similar question: Distance from a point to a polyhedron or to a polygon. However, the space is 2D in my case and the polygon can be concave, so it's somehow different from that one.
I suppose there should be a method simpler than offsetting the polygon by d and determining it's inside or outside the polygon.
Any algorithm, code, or hints for me to google around would be appreciated.
Your best bet is to iterate over all the lines and find the minimum distance from a point to a line segment.
To find the distance from a point to a line segment, you first find the distance from a point to a line by picking arbitrary points P1 and P2 on the line (it might be wise to use your endpoints). Then take the vector from P1 to your point P0 and find (P2-P1) . (P0 - P1) where . is the dot product. Divide this value by ||P2-P1||^2 and get a value r.
Now if you picked P1 and P2 as your points, you can simply check if r is between 0 and 1. If r is greater than 1, then P2 is the closest point, so your distance is ||P0-P2||. If r is less than 0, then P1 is the closest point, so your distance is ||P0-P1||.
If 0<r<1, then your distance is sqrt(||P0-P1||^2 - (r * ||P2-P1||)^2)
The pseudocode is as follows:
for p1, p2 in vertices:
var r = dotProduct(vector(p2 - p1), vector(x - p1))
//x is the point you're looking for
r /= (magnitude(vector(p2 - p1)) ** 2)
if r < 0:
var dist = magnitude(vector(x - p1))
else if r > 1:
dist = magnitude(vector(p2 - x))
else:
dist = sqrt(magnitude(vector(x - p1)) ^ 2 - (r * magnitude(vector(p2-p1))) ^ 2)
minDist = min(dist,minDist)
In the event that this helps someone else, I reverse engineered doverbin's answer to understand why it worked showing graphically what the three cases are computing. (doverbin, feel free to incorporate this into your answer if you wish.)
If you have a working point to line segment distance function, you can use it to calculate the distance from the point to each of the edges of the polygon. Of course, you have to check if the point is inside the polygon first.
Do you need fast or simple?
Does it have to be always absolutely correct in edge cases or will good enough most of the time be OK?
Typical solution are to find the distance to each vertex and find the pair with the smallest values ( note that for a point outside a convex polygon these might not be adjacent) and then check point to line intersections for each segment.
For large complex shapes you can also store approx polygon bounding boxes (either rectangular or hexagons) and find the closest side before checking more detail.
You may also need code to handle the special case of exactly on a line.
I can help you with this pointers:
The distance can be calculated using Wikipedia entry, even with an untested snipped of code.
The inside/outside border can be solved with this Stack Post and links
and some remarks:
you should check only the nearest points, as Martin Beckett´s answer point outs, since another segment can "proyected" very near, but in reality don´t be close as need.
I do not know about the difference in performance with respect to the rest of answers, but in boost C++ libraries there is an generic implementation called distance. It has information about complexity in every case and in your problem case it is linear.
I was also looking for solutions to this problem some days ago and I want to share this finding. Hope it helps to someone.
Related
I saw a lot of posts describing how to find if the point lies outside or inside. But I want to know if there's a way to know if the point is in the edge of the triangle.
The equation should have 4 parameters (p,x,y,z), the point which I try to discover lies on the edge and three other points that create the triangle
When I saw on edge, I mean on any of the segments, given a triangle "on edge" is any of the lines that create it
What does on the edge mean ?
Even if your end points and the point you pick are integers the equation of line is not. No point will ever be on the line to infinite precision (except for obvious cases)
It really only makes sense to say the point is within some small distance of the line. See Shortest distance between a point and a line segment for equations.
When you calculate postition of the point relative to triangle edge with function from linked answer:
float sign (fPoint p1, fPoint p2, fPoint p3)
{
return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
}
then zero sign value denotes that point lies exactly on the edge.
(More exactly - on the line containing edge. Signs for two other edges show whether point is between vertices)
If you need some tolerance level to compensate floating-point errors, just compare absolute "sign" value with triangle area.
DoubledTriangleArea = Abs(sign(v1, v2, v3)
if (Abs(sign(p, v1, v2)) / DoubledTriangleArea < SomeSmallValue)
p lies near v1-v2 edge
At the moment I try to learn and understand geometric algorithms and I found the smallest-circle-problem quite interesting. I found many solutions and different algorithms including this one of which I'm not sure if it is Emo Welzl's.
However, I don't understand one specific (important) part:
You're given N points on a (XY)-Plane.
You order those points randomly
Choose 3 points and create the circle where they are on the circle boundary.
Get the next point and check if it is enclosed by the circle:
a) If it is enclosed, repeat 4 until there are no more points left.
b) If is not enclosed, create a new circle where the new point is on the circle boundary and still all other points are inside or on the circle.
Steps 1) to 4a) are simple, my problem is step 4b). How can I find this new circle? To me, it seems like this is the same problem just with a smaller (sub)set of points. (Divide-et-Impera)
I guessed I have to replace one of the 3 original points (the first 3 points, that made up the first circle) with the new point, but I'm not sure
if this really works...
From the 3 points A,B,C you can calculate the centre O of the circle: the point that is equidistant to those three. Its coordinates xO and yO are the means of xA,xB,xC and yA, yB, yC respectively.
Let's call D the 4th point, trace the circle of centre 0 and radius OD.
OD > OA (and OA=OB=OC) so A, B and C are in the circle.
EDIT
The solution I proposed above is not optimal.
I found a good explanation of Welzl's algorithm: see link
Of course, you can get his paper easily by looking on Google Scholar, but it is quite hard to read.
The basic principle is that in 4b) the circle is computed from all the possible circles having D on the boundary as well as two other points that were on the boundary before (or one point if that doesn't work and it will be diametrically opposed to D).
In
http://en.wikipedia.org/wiki/Closest_pair_of_points_problem
we can see that it mentions that is at most 6 points that is closest to the point on the other half, which can be represented as the graph below:
My question is for point P1 and Point P2, the distance to the red point will exceed sqrt(2)*d, why it is part of the solution? Why it is not at most 4 points that is closest to P rather than at most 6 points? Thanks.
P1 and P2 are not part of the solution, but they have to be examined on the way to the solution, because the algorithm examines all points in the box, and P1 and P2 are in the box.
Note that no such point as your Q can exist, because by hypothesis the minimum distance between points in the right-hand half of the diagram is d.
Edited to add: you seem to think that the Wikipedia article is making a claim like this:
There may be up to 6 points on the right side of the line that are within a distance d of P.
This claim would be false. But the article does not make such a claim. Instead, it makes two separate claims, both of which are true:
All the points on the right side of the line that are within a distance d of P are inside the box.
There may be up to 6 points in the box.
We are only counting the maximum number of points that can lie in the right d x 2d rectangle. Since any two points are constrained to have a minimum distance of d, we can place at most 6 points in the rectangle while satisfying this constraint, as shown in the figure.
Note that the points on the right side that are within d distance from P should all lie within a circular segment of a circle centered at P and whose radius is d. There can be at most 4 points in this segment. However, finding the number of points within a segment is more complicated than finding the number of points within a rectangle. So we use the rectangle instead and incur an extra cost of having to search for at most 2 additional points.
The bound is only important for complexity estimation. Code-wise, you may simply scan up and down within the distance dRmin. The bound here suggest that you'll at most see 6 points in each such scan, making this O(1).
Given a list of N points in the plane in general position (no three are collinear), find a new point p that is not collinear with any pair of the N original points.
We obviously cannot search for every point in the plane, I started with finding the coincidence point of all the lines that can be formed with the given points, or making a circle with them something.. I dont have any clue how to check all the points.
Question found in http://introcs.cs.princeton.edu/java/42sort/
I found this question in a renowned algorithm book that means it is answerable, but I cannot think of an optimal solution, thats why I am posting it here so that if some one knows it he/she can answer it
The best I can come up with is an N^2 algorithm. Here goes:
Choose a tolerance e to control how close you're willing to come to a line formed from the points in the set.
Compute the convex hull of your set of points.
Choose a line L parallel to one of the sides of the convex hull, at a distance 3e outside the hull.
Choose a point P on L, so that P is outside the projection of the convex hull on L. The projection of the convex hull on L is an interval of L. P must be placed outside this interval.
Test each pair of points in the set. For a particular line M formed by the 2 test points intersects a disc of radius 2e around P, move P out further along L until M no longer intersects the disc. By the construction of L, there can be no line intersecting the disk parallel to L, so this can always be done.
If M crosses L beyond P, move P beyond that intersection, again far enough that M doesn't pass through the disc.
After all this is done, choose your point at distance e, on the perpendicular to L at P. It can be colinear with no line of the set.
I'll leave the details of how to choose the next position of P along L in step 5 to you,
There are some obvious trivial rejection tests you can do so that you do more expensive checks only with the test line M is "parallel enough" to L.
Finally, I should mention that it is probably possible to push P far enough out that numerical problems occur. In that case the best I can suggest is to try another line outside of the convex hull by a distance of at least 3e.
You can actually solved it using a simple O(nlogn) algorithm, which we will then improve to O(n). Name A the bottom most point (in case of tie choose the one that is has smaller x coordinate). You can now sort in clockwise order the rest of the points using the CCW. Now as you process each point from the sorted order you can see that between any two successive points having different angle with point A and the bottom axis (let these be U, V) there is no point having angle c, with U <= c <= V. So we can add any point in this section and it is guaranteed that it won’t be collinear with any other points from the set.
So, all you need is to find one pair of adjacent points and you are done. So, find the minimum and the second minimum angle with A (these should be different) in O(n) time and select any point in between them.
I have a bounding box, and a number of points inside of it. I'd like to add another point whose location is farthest away from any previously-added points, as well as far away from the edges of the box.
Is there a common solution for this sort of thing? Thanks!
Here is a little Mathematica program.
Although it is only two lines of code (!) you'll probably need more in a conventional language, as well as a math library able to find maximum of functions.
I assume you are not fluent in Mathematica, so I'll explain and comment line by line.
First we create a table with 10 random points in {0,1}x{0,1}, and name it p.
p = Table[{RandomReal[], RandomReal[]}, {10}];
Now we create a function to maximize:
f[x_, y_] = Min[ x^2,
y^2,
(1 - x)^2,
(1 - y)^2,
((x - #[[1]])^2 + (y - #[[2]])^2) & /# p];
Ha! Syntax got tricky! Let's explain:
The function gives you for any point in {0,1}x{0,1} the minimum distance from that point to our set p AND the edges. The first four terms are the distances to the edges and the last (difficult to read, I know) is a set containing the distance to all points.
What we will do next is maximizing this function, so we will get THE point where the minimum distance to our targets in maximal.
But first lets take a look at f[]. If you look at it critically, you'll see that it is not really the distance, but the distance squared. I defined it so, because that way the function is much easier to maximize and the results are the same.
Also note that f[] is not a "pretty" function. If we plot it in {0,1}, we get something like:
That's why you will need a nice math package to find the maximum.
Mathematica is such a nice package, that we can maximize the thing straightforward:
max = Maximize[{f[x, y], {0 <= x <= 1, 0 <= y <= 1}}, {x, y}];
And that is it. The Maximize function returns the point, and the squared distance to its nearest border/point.
HTH! If you need help translating to another language, leave a comment.
Edit
Although I'm not a C# person, after looking for references in SO and googling, came to this:
One candidate package is DotNumerics
You should follow the following example provided in the package:
file: \DotNumerics Samples\Samples\Optimization.cs
Example header:
[Category("Constrained Minimization")]
[Title("Simplex method")]
[Description("The Nelder-Mead Simplex method. ")]
public void OptimizationSimplexConstrained()
HTH!
The name of the problem you're solving is the largest empty sphere problem.
It can easily be solved in O(n^4) time in the plane. Just consider all O(n^3) triples of points and compute their circumcenter. One of these points is your desired point. (Well, in your case, you also have to consider "a side" as one of your three points, so you not only find circumcenters but slightly more general points, like ones equidistant from two points and a side.)
As the Wikipedia link above indicates, the problem can also be solved in O(n log n) time by computing a Voronoi diagram. More specifically, then your desired point is the circumcenter of one of the triangles in the Delaunay triangulation of your points (which is the dual of the Voronoi diagram), of which there are only O(n). (Again, to adapt exactly to your problem, you'll have to consider the effects of the sides of the box.)