Calculate the Signed Distance Transform of arbitrary polygon - c++

How would you calculate the Signed Distance Function of a polygon, described by an arbitrary set of points. The polygon could be concave or convex. Assume that the points are stored in a std::vector with counter-clockwise winding.
Update
Let me be more specific. This is not a sampled function on a grid. I need to be able to detect a sign change along an arbitrary line segment drawn through (not necessarily intersecting) the polygon, without checking individual intersections with each line segment. The problem is, I might have thousands of line segments.
Can anyone think of an efficient way of doing this?
If I can parametrically express the SDF, I can calculate a derivative to accomplish this.

Bad news: in the worst case, a line segment can intersect the polygon in N points, and this can arise for all M line segments. So in the worst case, exhaustive comparison of the segments vs. the sides is unavoidable. This goes in favor of the brute-force approach.
Fortunately, output-sensitive solutions are known for the problem of the intersection of N line segments, using the sweepline approach. The complexity can be lowered to O((N+K) log N) or O(N log N + K) where K is the number of intersections found.

Firstly rotate all the points so the line is parallel with the x axis. Then translate so that the line is the x axis. Then as a test integrate. The area under a straight line x0y0 x1y1 is pretty simple to calculate. You can sum all the expressions to get the indefinite integral, or signed area, which should be independent of axis (because points under the curve subtract). Now to answer the specific question, sort in x to enable you to find the point value at a given x. So create two "events", section start, and section "end" with a pointer or reference back to the start event. Then to get the distance transform at any point, we calculate all the events the cross the x of interest. If you want piecewise functions to each event interval, that's actually slightly easier as you can pass through the queue from start to end.

Related

Polygon Detection from a Set of Lines?

I have a set of connected, intersecting line segments. I want to detect all polygons that result from the intersection of these line segments, as follows:
I found a paper that presents an algorithm for solving this problem, but I'm not really a computer science person so I wasn't able to understand it. Here's a link to the paper. At this moment, my plan is to 1) find all intersections, and 2) somehow use these intersections to identify the polygons. I'm able to solve (1) through brute force, but (2) is a bit trickier. I'd prefer a solution in R or C++, but any language will do.
Assuming you have your line segments always as a closed polygonal chain and you have them in some sort of edge list. And, as you said, you have the intersection points already computed (brute force means O(n^2) time, in this case that is optimal as the line segments can intersect n^2 times).
You can insert your intersection points from (1) into this list splitting the intersecting line segments, mark them as intersection points and reference to all intersecting line segments in this point. Furthermore, on every line segment two polygons are incident, thus add respective reference fields to every edge. Then just take the leftmost vertex in you input and walk along the edge list. Add to every edge that is traversed a reference to its left incident polygon (in this case) polygon number one. If you reach an intersection point, put it on some sort of stack for later recovery. Now analyse that point and continue walking on the leftmost path (between the line segment on which you reached the intersection point and all outgoing segments). At some point you reach your starting point and you have the first simple polygon closed.
Now take the first intersection point from the stack. There must be an even number of line segments that start/end there. Find a line segment that has at most one incident polygon referenced (yet) and use it as as starting segment for polygon number two. You can walk along its chain in the same manner as before. (If you reference a line segment`s right incident polygon, take the rightmost turn on an intersection point.) When your stack ist empty your are done.
Edit: After I looked one more time for a solution I found this implementation from Dan Sunday. I assume that is more useful as it is also already implemented.
Alfredo Ferreira developed c++ code for detecting polygons from a set of overlapping lines. You can find the code at his page here: http://3dorus.ist.utl.pt/tools/PolygonDetector.html
Hope this Helps
I just published my implementation which is extremely fast after trying the algo from the paper.
The basic idea is to remove the detected cycles and redo the search (remove the “ears” of the detected cycle).
I am also unsing just the line segments that have connected points to the graph. The overlapping are removed in two steps: by using the area formula, which is pretty much exact and then approximate the intersection points difference in a specific range.
https://github.com/realuptime/PolyDetector

Fit rectangle around points

I'm trying to fit a rectangle around a set of 8 2D-Points, while trying to minimize the covered area.
Example:
The rectangle may be scaled and rotated. However it needs to stay a rectangle.
My first approach was to brute force each possible rotation, fit the rectangle as close as possible, and calculate the covered area. The best fit would be then the rotation with the lowest area.
However this does not really sound like the best solution.
Is there any better way for doing this?
I don't know what you mean by "try every possible rotation", as there are infinitely many of them, but this basic idea actually yields a very efficient solution:
The first step is to compute the convex hull. How much this actually saves depends on the distribution of your data, but for points picked uniformly from a unit disk, the number of points on the hull is expected to be O(n^1/3). There are a number of ways to do that:
If the points are already sorted by one of their coordinates, the Graham scan algorithm does that in O(n). For every point in the given order, connect it to the previous two in the hull and then remove every concave point (the only candidate are those neighboring the new point) on the new hull.
If the points are not sorted, the gift-wrapping algorithm is a simple algorithm that runs at O(n*h). For each point on the hull starting from the leftmost point of the input, check every point to see if it's the next point on the hull. h is the number of points on the hull.
Chen's algorithm promises O(n log h) performance, but I haven't quite explored how it works.
another simle idea would be to sort the points by their azimuth and then remove the concave ones. However, this only seems like O(n+sort) at first, but I'm afraid it actually isn't.
At this point, checking every angle collected thus far should suffice (as conjenctured by both me and Oliver Charlesworth, and for which Evgeny Kluev offered a gist of a proof). Finally, let me refer to the relevant reference in Lior Kogan's answer.
For each direction, the bounding box is defined by the same four (not necessarily distinct) points for every angle in that interval. For the candidate directions, you will have at least one arbitrary choice to make. Finding these points might seem like an O(h^2) task until you realise that the extremes for the axis-aligned bounding box are the same extremes that you start the merge from, and that consecutive intervals have their extreme points either identical or consecutive. Let us call the extreme points A,B,C,D in the clockwise order, and let the corresponding lines delimiting the bounding box be a,b,c,d.
So, let's do the math. The bounding box area is given by |a,c| * |b,d|. But |a,c| is just the vector (AC) projected onto the rectangle's direction. Let u be a vector parallel to a and c and let v be the perpendicular vector. Let them vary smoothly across the range. In the vector parlance, the area becomes ((AC).v) / |v| * ((BD).u) / |u| = {((AC).v) ((BD).u)} / {|u| |v|}. Let us also choose that u = (1,y). Then v = (y, -1). If u is vertical, this poses a slight problem involving limits and infinities, so let's just choose u to be horizontal in that case instead. For numerical stability, let's just rotate 90° every u that is outside (1,-1)..(1,1). Translating the area to the cartesian form, if desired, is left as an exercise for the reader.
It has been shown that the minimum area rectangle of a set of points is collinear with one of the edges of the collection's convex hull polygon ["Determining the Minimum-Area Encasing Rectangle for an Arbitrary Closed Curve" [Freeman, Shapira 1975]
An O(nlogn) solution for this problem was published in "On the computation of minimum encasing rectangles and set diameters" [Allison, Noga, 1981]
A simple and elegant O(n) solution was published in "A Linear time algorithm for the minimum area rectangle enclosing a convex polygon" [Arnon, Gieselmann 1983] when the input is the convex hull (The complexity of constructing a convex hull is equal to the complexity of sorting the input points). The solution is based on the Rotating calipers method described in Shamos, 1978. An online demonstration is available here.
They first thing that came to mind when I saw this problem was to use principal component analysis. I conjecture that the smallest rectangle is the one that satisfies two conditions: that the edges are parallel with the principal axes and that at least four points lie on the edges (bounded points). There should be an extension to n dimensions.

Finding "how straight" is a shape. openCV

I'm working on an application were I have a set of Contours(each one representing a Potential Line) and I wanna check "How straight" is that contour/shape.
The article I am using as a refrence uses the following technique:
It Matches a "segmented" line crossing the shape like so-
Then grading how "straight" is the line.
Heres an example of the Contours I am working on:
How would you go about implementing this technique?
Is there any other way of checking "How Straight" is a contour\shape?
Regards!
My first guess would be to use a coefficient of determination. That would be, fit a linear line to all your point assuming some reasonable origin where you won't receive rounding errors and calculate R^2.
A more advanced approach, if all contours are disconnected components, would be to calculate the structure model index (the link is for bone morphometry, but they explain the concept and cite the original paper.) This gives you a number that tells you how much your segment is "like a rod". This is just an idea, though. Anything that forms curves or has branches will be less and less like a rod.
I would say that it also depends on what you are using the metric for and if your contours are always generally carrying left to right.
An additional method would be to create the covariance matrix of your points, calculate the eigenvalues from that matrix, and take their ratio (where the ratio is greater than or equal to 1; otherwise, invert the ratio.) This is the basic principle behind a PCA besides the final ratio. If you have a rather linear data set (the data set varies in only one direction) then you will have a very large ratio. As the data set becomes less and less linear (or more uncorrelated) you would see the ratio approach one. A perfectly linear data set would be infinity and a perfect circle one (I believe, but I would appreciate if someone could verify this for me.) Also, working in two dimensions would mean the calculation would be computationally cheap and straight forward.
This would handle outliers very well and would be invariant to the rotation and shape of your contour. You also have a number which is always positive. The only issue would be preventing overflow when dividing the two eigenvalues. Then again you could always divide the smaller eigenvalue by the larger and your metric would be bound between zero and one, one being a circle and zero being a straight line.
Either way, you would need to test if this parameter is sensitive enough for your application.
One example for a simple algorithm is using the dot product between two segments to determine the angle between them. The formula for dot product is:
A * B = ||A|| ||B|| cos(theta)
Solving the equation for cos(theta) yields
cos(theta) = (A * B / (||A|| ||B||))
Since cos(0) = 1, cos(pi) = -1.0 and you're checking for the "straightness" of the lines, a line whose normalization of cos(theta) angles is closest to -1.0 is the straightest.
straightness = SUM(cos(theta))/(number of line segments)
where a straight line is close to -1.0, and a non-straight line approaches 1.0. Keep in mind this is a cursory evaluation of this algorithm and it obviously has edge cases and caveats that would need to be addressed in an implementation.
The trick is to use image moments. In short, you calculate the minimum inertia around an axis, the inertia around an axis perpendicular to this, and the ratio between them (which is always between 0 and 1; since inertia is non-negative)
For a straight line, the inertia along the line is zero, so the ratio is also zero. For a circle, the inertia is the same along all axis so the ratio is one. Your segmented line will be 0.01 or so as it's a fairly good match.
A simpler method is to compare the circumference of the the convex polygon containing the shape with the circumference of the shape itself. For a line, they're trivially equal, and for a not too crooked shape it's still comparable.

Algorithms for Collision Detection between Arbitrarily sized Convex Polygons

I am working on an asteroids clone. Everything is 2D, and written in C++.
For the asteroids, I am generating random N-sided polygons. I have guaranteed that they are Convex. I then rotate them, give them a rotspeed, and have them fly through space. It all works, and is very pretty.
For collision, I'm using an Algorithm I thought of myself. This is probably a bad idea, and if push comes to shove, I'll probably scrap the whole thing and find a tutorial on the internet.
I've written and implemented everything, and the collision detection works alright.... most of the time. It will randomly fail when there's obviously a collision on screen, and sometimes indicate collision when nothing is touching. Either I have flubbed my implementation somewhere, or my algorithm is horrible. Due to the size/scope of my implementation (over several source files) I didn't want to bother you with that, and just wanted someone to check that my algorithm is, in fact, sound. At that point I can go on a big bug hunt.
Algorithm:
For each Asteroid, I have a function that outputs where each vertex should be when drawing the asteroid. For each pair of adjacent Vertices, I generate the Formula for the line that they sit on, y=mx+b format. I then start with one of my ships vertices, testing that point to see whether it is inside the asteroid. I start by plugging in the X coordinate of the point, and comparing the output to the Actual Y value. This tells me if the point is above or below the line. I then do the same with the Center of the Asteroid, to determine which half of the line is considered "Inside" the asteroid. I then repeat for each pair of Vertices. IF I ever find a line for which my point is not on the same side as the center of the asteroid, I know there is no collision, and exit detection for that point. Since there are 3 points on my ship, I then have to test for the next point. If all 3 points exit early, then There are no collisions for any of the points on the ship, and we're done. If any point is bound on all sides by the lines made up by the asteroid, then it is inside the asteroid, and the collision flag is set.
The two Issues I've discovered with this algorithm is that:
it doesn't work on concave polygons, and
It has problems with an Edge case where the Slope is Undefined.
I have made sure all polygons are Convex, and have written code to handle the Undefined Slope issue (doubles SHOULD return NAN if we divide by 0, so it's pretty easy to test for that).
So, should this work?
The standard solution to this problem is using the separating axis theorem (SAT). Given two convex polygons, A and B, the algorithm basically goes like this:
for each normal N of the edges of A and B
intervalA = [min, max] of projecting A on N
intervalB = [min, max] of projecting B on N
if intervalA doesn't overlap intervalB
return did not collide
return collided
I did something similar to compute polygon intersections, namely finding if a vertex sits within a given polygon.
Your algorithm is sound, and indeed does not work for concave polys. The line representation you chose is also problematic at slopes approaching infinity. I chose to use a couple of vectors for mine, one for the line direction, and one for a reference point on the line. From these, I can easily derive a parameterized equation of the line, and use that in various ways to find intersections with other shapes.
P = S + t * D
Any point P of the line can be caracterized by its coordinate t on the the line, given the above relation, where S is the reference point, and D the direction vector.
This representation lets you easily define which parts of the plane is the positive and the negative one (ie. above and below the line), thanks to the direction orientation. Now, any region of the plane can be defined as an intersection of several lines' negative or positive subplanes. So your "point within polygon" algorithm could be slightly changed to use that representation, with the added constraint of all the direction pointing clockwise, and testing for the point being in the negative subplane of all the lines (so you don't need the centre of the polygon anymore).
The formula to compute the side of a point wrt a line I used is the following:
(xs - xp) * yd - (ys - yp) * xd
The slope issue appears here when point P is close to S.
That representation can be computed using the edge vertices, but in order to have correct subplanes, you must keep your vertices in your polygon in condecutive orders.
For concave polygons, the problem is a bit more complicated: briefly, you have to test that the point is between two consecutive convex edges. This can be achieved by checking the coordinate of the point on the edge when projected on it, and ensuring it stands between 0 and length(edge) (assuming that the direction is normalized). Note that it boils down to check if the point belongs to a triangle within the polygon.

Estimating equation for plane if distances to various points on it are known

I know the distance to various points on a plane, as it is being viewed from an angle. I want to find the equation for this plane from just that information (5 to 15 different points, as many as necessary).
I will later use the equation for the plane to estimate what the distance to the plane should be at different points; in order to prove that it is roughly flat.
Unfortunately, a google search doesn't bring much up. :(
If you, indeed, know distances and not coordinates, then it is ill-posed problem - there is infinite number of planes that will have points with any number of given distances from origin.
This is easy to verify. Let's take shortest distance D0, from set of given distances {D0..DN-1} , and construct a plane with normal vector {D0,0,0} (vector of length D0 along x-axis). For each of remaining lengths we now have infinite number of points that will lie in this plane (forming circles in-plane around (D0,0,0) point). Moreover, we can rotate all vectors by an arbitrary angle and get a new plane.
Here is simple picture in 2D (distances to a line; it's simpler to draw ;) ).
As we can see, there are TWO points on the line for each distance D1..DN-1 > D0 - one is shown for D1 and D2, and the two other for these distances would be placed in 4th quadrant (+x, -y). Moreover, we can rotate our line around origin by an arbitrary angle and still satisfy given distances.
I'm going to skip over the process of finding the best fit plane, it's been handled in some other answers, and talk about something else.
"Prove" takes us into statistical inference. The way this is done is you make a formal hypothesis "the surface is flat" and then see if the data supports rejecting this hypothesis at some confidence level.
So you can wind up saying "I'm not even 1% sure that the surface isn't flat" -- but you can't ever prove that it's flat.
Geometry? Sounds like a job for math.SE! What form will the equation take? Will it be a plane?
I will assume you want an accurate solution.
Find the absolute positions with geometry
Make a best fit regression line in C++ in 2 of the 3 dimensions.