Arduino convex hull algorithm - 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.

Related

3D mesh direction detection

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.

How do I determine label offset so the label is always on the outside of a polygon?

I'm have some vertices of a polygon with labels on them. I want to place the labels so that they are always on the outside of the polygon. So in the image above, all of the labels are fine except for #3 and #4, which I want to be on the bottom, outside of the polygon. So generally, how do I determine, for a particular vertex, how to offset it such that it's outside the polygon?
Since you do not show any code of your own, I will just state some ideas. If you want more details including code, show more effort of your own then ask.
I'll assume here that the polygon is assumed to be a simple polygon--one that does not intersect itself. If a polygon does intersect itself, the definition of its "inside" is not so straightforward and there are multiple definitions of the inside. I will not assume that the polygon is convex--all the interior angles are less than 180°. (That would allow an easier answer.) I'll also assume that you want the center of your label to be outside the polygon but will allow a corner or small part of the label to be inside.
First, traverse the polygon and find its "winding angle," the amount the direction angle changes during the traversal. If the polygon is simple, the angle will be either +180° or -180°. One of those means you traversed the polygon clockwise, the other one means counter-clockwise. (Which is which depends on your coordinate system: Cartesian or graphing or other.)
Then traverse the polygon again. Now that you know the direction of the polygon, at each vertex you can find whether the exterior angle goes clockwise or counterclockwise from the entering segment. Find that direction and the size of the angle, then move half that angle in that direction. Move a given distance from the vertex along that angle, and you have the position of the center of your label.
That should work well for the vast majority of polygons. In some edge cases for non-convex polygons, that location moved away from the polygon into another part of the polygon. You then reduce the distance the label is from its vertex until the label moves back into the polygon's outside.
I gave an answer to a related question: How do I efficiently determine if a polygon is convex, non-convex or complex?.
On every vertex, the incoming and outgoing edges form an angle that covers some sector. You can place the label at some distance along the bisector of this angle. You find the direction vector of the bisector by adding two unit vectors originating from the vertex in the directions of the edges.
Finding the correct bisector side requires some care. In the first place, you need to orient the polygon, i.e. check if it is clockwise or counterclockwise. This is simply done by computing the area with the shoelace formula and testing the sign.
Then, if I am right, you can test the area of triangle formed by the two edges and compare its sign to that of the whole polygon. This tells you if the angle is convex or reflex, and you know the proper side. For a convex polygon, the side is always negative for a vector computed as above.
Maybe follow something like this: First, make sure the polygon does not self-intersect, see the previous answers. Then, let the polygon be counter-clockwise oriented and represented by an array (a 2 by n+2 matrix) of its vertices (the vertices are traversed in counter-clockwise order)
double P[n+2][2] = {{pxn, pyn}, {px1, py1}, {px2, py2}, ..., {pxn, pyn}, {px1, py1}};
double Label_position[n][2];
void generate_labels(const double (&P)[n+2][2], double (&Label_position)[n][2]){
double v1[2];
double v2[2];
for(j = 1, j <= n, j = j+1) {
v1[0] = P[j][0] - P[j-1][0];
v1[1] = P[j][1] - P[j-1][1];
v2[0] = P[j+1][0] - P[j][0];
v2[1] = P[j+1][1] - P[j][1];
v1 = normalize(v1);
v2 = normalize(v2);
t = add_vectors(v1, v2);
t = normalize(t);
Label_position[j][0] = t[1] + P[j][0];
Label_position[j][1] = - t[0] + P[j][1];
}
}
This function generates the coordinates of the points at the tips of the unit angle bisector vectors pointing in the exterior of the polygon (see Yves Daoust's answer and the picture he has generated).

collision prediction using minkowski sum

I want to use the minkowski sum to predict the exact point of collision between two convex shapes. By my understanding the point where the velocity vector intersects with the minkowski sum is the amount I have to move my object along the vector so they just touch (I already know they will collide). Here's an example of what I mean (for simplicity reasons I just used rectangles):
I mean I could just calculate the intersection with every line of the convex hull and just use the closest but that seems horribly inefficient. My idea was to calculate the simplex closest to the vector but I have no idea how best to do it. I found a algorithm which calculates the smallest distance between to objects or to be more precise the smallest distance from the minkowski sum to the origin (http://www.codezealot.org/archives/153). One part of the algorithm tries to find the simplex closest to origin which is kinda what I want to do. I tried to change it to my needs but I wasn't successful. To me it sounds like there should be a very simple solution but I am not that good with vector math.
I hope I could make my problem clear since my english is not so good :D
You can transform the problem as follows:
1) rotate the plane so that the velocity vector becomes horizontal
2) consider the portions of the polygon outlines facing each other (these are two convex polylines); now you have to find the shortest horizontal distance between these two polylines
3) through every vertex of one of the polylines, draw an horizontal line; this will parition the plane into a set of horizontal slices
4) transform every slice using a shear transformation that brings the two vertices defining it onto the Y axis by horizontal moves; this transform preserves horizontal distances
5) while the first polyline is transformed into a straight line (the Y axis), the other polyline is transformed into another polyline; find the vertex(es) closest to the Y axis. This gives you the length of the collision vector.
As a by-product, step 2) will tell you if the polygons do collide, if the ranges of Y values overlap.

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.)

Find the largest convex black area in an image

I have an image of which this is a small cut-out:
As you can see it are white pixels on a black background. We can draw imaginary lines between these pixels (or better, points). With these lines we can enclose areas.
How can I find the largest convex black area in this image that doesn't contain a white pixel in it?
Here is a small hand-drawn example of what I mean by the largest convex black area:
P.S.: The image is not noise, it represents the primes below 10000000 ordered horizontally.
Trying to find maximum convex area is a difficult task to do. Wouldn't you just be fine with finding rectangles with maximum area? This problem is much easier and can be solved in O(n) - linear time in number of pixels. The algorithm follows.
Say you want to find largest rectangle of free (white) pixels (Sorry, I have images with different colors - white is equivalent to your black, grey is equivalent to your white).
You can do this very efficiently by two pass linear O(n) time algorithm (n being number of pixels):
1) in a first pass, go by columns, from bottom to top, and for each pixel, denote the number of consecutive pixels available up to this one:
repeat, until:
2) in a second pass, go by rows, read current_number. For each number k keep track of the sums of consecutive numbers that were >= k (i.e. potential rectangles of height k). Close the sums (potential rectangles) for k > current_number and look if the sum (~ rectangle area) is greater than the current maximum - if yes, update the maximum. At the end of each line, close all opened potential rectangles (for all k).
This way you will obtain all maximum rectangles. It is not the same as maximum convex area of course, but probably would give you some hints (some heuristics) on where to look for maximum convex areas.
I'll sketch a correct, poly-time algorithm. Undoubtedly there are data-structural improvements to be made, but I believe that a better understanding of this problem in particular will be required to search very large datasets (or, perhaps, an ad-hoc upper bound on the dimensions of the box containing the polygon).
The main loop consists of guessing the lowest point p in the largest convex polygon (breaking ties in favor of the leftmost point) and then computing the largest convex polygon that can be with p and points q such that (q.y > p.y) || (q.y == p.y && q.x > p.x).
The dynamic program relies on the same geometric facts as Graham's scan. Assume without loss of generality that p = (0, 0) and sort the points q in order of the counterclockwise angle they make with the x-axis (compare two points by considering the sign of their dot product). Let the points in sorted order be q1, …, qn. Let q0 = p. For each 0 ≤ i < j ≤ n, we're going to compute the largest convex polygon on points q0, a subset of q1, …, qi - 1, qi, and qj.
The base cases where i = 0 are easy, since the only “polygon” is the zero-area segment q0qj. Inductively, to compute the (i, j) entry, we're going to try, for all 0 ≤ k ≤ i, extending the (k, i) polygon with (i, j). When can we do this? In the first place, the triangle q0qiqj must not contain other points. The other condition is that the angle qkqiqj had better not be a right turn (once again, check the sign of the appropriate dot product).
At the end, return the largest polygon found. Why does this work? It's not hard to prove that convex polygons have the optimal substructure required by the dynamic program and that the program considers exactly those polygons satisfying Graham's characterization of convexity.
You could try treating the pixels as vertices and performing Delaunay triangulation of the pointset. Then you would need to find the largest set of connected triangles that does not create a concave shape and does not have any internal vertices.
If I understand your problem correctly, it's an instance of Connected Component Labeling. You can start for example at: http://en.wikipedia.org/wiki/Connected-component_labeling
I thought of an approach to solve this problem:
Out of the set of all points generate all possible 3-point-subsets. This is a set of all the triangles in your space. From this set remove all triangles that contain another point and you obtain the set of all empty triangles.
For each of the empty triangles you would then grow it to its maximum size. That is, for every point outside the rectangle you would insert it between the two closest points of the polygon and check if there are points within this new triangle. If not, you will remember that point and the area it adds. For every new point you want to add that one that maximizes the added area. When no more point can be added the maximum convex polygon has been constructed. Record the area for each polygon and remember the one with the largest area.
Crucial to the performance of this algorithm is your ability to determine a) whether a point lies within a triangle and b) whether the polygon remains convex after adding a certain point.
I think you can reduce b) to be a problem of a) and then you only need to find the most efficient method to determine whether a point is within a triangle. The reduction of the search space can be achieved as follows: Take a triangle and increase all edges to infinite length in both directions. This separates the area outside the triangle into 6 subregions. Good for us is that only 3 of those subregions can contain points that would adhere to the convexity constraint. Thus for each point that you test you need to determine if its in a convex-expanding subregion, which again is the question of whether it's in a certain triangle.
The whole polygon as it evolves and approaches the shape of a circle will have smaller and smaller regions that still allow convex expansion. A point once in a concave region will not become part of the convex-expanding region again so you can quickly reduce the number of points you'll have to consider for expansion. Additionally while testing points for expansion you can further cut down the list of possible points. If a point is tested false, then it is in the concave subregion of another point and thus all other points in the concave subregion of the tested points need not be considered as they're also in the concave subregion of the inner point. You should be able to cut down to a list of possible points very quickly.
Still you need to do this for every empty triangle of course.
Unfortunately I can't guarantee that by adding always the maximum new region your polygon becomes the maximum polygon possible.

Resources