How to determine two polygons is same? - javascript

I have a polygon, it has five points like this:
then I add another point to polygon (the red one):
what's the algorithm to determine two polygons is same one (not just angle/length is same, coordinates also same too).

As your same means same shape,size,orientation and position
then it is really simple
you have 2 polygons defined as set of points
A={ a0,a1...a(n-1) } and B={ b0,b1,...b(m-1) }
for starters I assume you have no oversampling (line is always 2 points not more)
compare m,n
if not equal shapes are different so stop
otherwise m==n so I will use just n from now on
find (a(i)==b(j)) where i,j=<0,n)
this is needed in case the polygons are not starting from the same point
otherwise i=0,j=0
for complicated (self intersecting) shapes you need to find unique points
(not duplicates, or the same count of duplicates with the same next point)
otherwise just set i=0 and find j with single O(n) loop
if no common point found stop (not the same polygons)
compare the points
for (k=0;k<n;k++)
{
if (a(i)!=b(j)) return false; // not the same
i++; if (i>=n) i=0;
j++; if (j>=n) j=0;
} return true; // are the same
the point comparison can be done like this if (|a(i)-b(j)|>=max_difference_treshold)
no need to compare sqrt-ed distances the treshold can be powered by 2 instead
I usually use something like 1e-6 or 1e-10 values
For oversampled polygon you need to resample points of booth A,B first
take 3 neighboring points p(i-1),p(i),p(i+1)
compute dx,dy between 2 pairs
d1=p(i)-p(i-1); dx1=p1.x; dy1=p1.y;
d2=p(i+1)-p(i); dx2=p2.x; dy2=p2.y;
if (dx1*dy2==dx1*dy1) then delete p(i) from the set
you should handle the zero cases (any dx,dy is zero) separately prior to this

//import turf library
var turf = require('#turf/turf');
// create polygon using turf or you can directly use geoJSON
var polygon1 = turf.polygon(firstPolygonCoordinates);
var polygon2 = turf.polygon(secondPolygonCoordinates);
// Compare two polygon using turf's booleanEqual method
if (turf.booleanEqual(polygon1, polygon2)) {
// Add your logic here
}

Depending on your point of view. Two rectangles may be the same independently of the position.
If the position is a requirement you will need to compare the vertex
coordinates.
If the position is NOT a requirement, you should compare the
rectangle size. In this case, you need to obtain the distance between
the vertex. In this case, my advice is you should use the rectangle
base and height for comparing.

Related

Find the largest rectangle that fits inside a polygon

I need to find the largest rectangle that can fit inside any polygon,
what i tried is dividing the svg to 2d grid and loop the 2d array to see if the current grid cell intersects with the polygon to create a new 2d binary array where intersection is 1 else 0
now i need to find the largest rectangle from that 2d array AND more importantly its location
as example:
if the 2d array is like this, i need to find the largest rect in that array and its x1,y1 (start i,j) and x2,y2 (end i,j).
well you can brute force the location and scan for the size which will be O(n^6) if n is the avg size of side of your map in pixels ...
The location might be speed up by search (accepting not strictly sorted data) for example like this:
How approximation search works
which would lead to ~O(n^4.log^2(n)). But beware the search must be configured properly in order to not skip solution ... The size search can be improved too by using similar technique like I did in here:
2D OBB
Just use different metric so I would create LUT tables of start and end positions for each x and y (4 LUT tables) which will speed up the search leading to ~O(n^2.log^2(n)) while creation of LUT is O(n^2). btw the same LUTs I sometimes use in OCR like here (last 2 images):
OCR and character similarity
Now problem with this approach is it can not handle concave polygon correctly as there might be more edges per x,y than just 2. So to remedy that you would need to have more LUTs and use them based on position in polygon (divide polygon to "convex" areas)
So putting all these together would look something like this:
approx loop (center x) // ~O(log(n))
approx loop (center y) // ~O(log(n))
grow loop (square size to max using) LUT // O(n)
{
grow loop (x size to max while decreasing original square y size) // O(n)
grow loop (y size to max while decreasing original square x size) // O(n)
use bigger from the above 2 rectangles
}
Just do not forget to use area of polygon / area of rectangle as approximation error value. This algo is resulting in ~O(n^2.log^2(n)) which is not great but still doable.
Another option is convert your polygon to squares, and use bin-packing and or graph and or backtracking techniques to grow to biggest rectangle ... but those are not my cup of tea so I am not confident enough to create answer about them.

Check if a line drawn intersects or inside the existing polygon on html canvas

Check if a line drawn intersects or inside the existing polygon on html canvas.
I have a html canvas and there is polygon (mainly quadrilateral) which is already drawn. Now if a straight line is drawn on the canvas I have to check if it intersects the polygon's any side or it is inside the polygon. If any of these is true (intersects or inside) I have to return true.
I am writing code on Angular.
I assume that you mean line segment rather than infinite line.
You can check whether segment intersects any polygon edge (check them all) with intersection detection algorithm (arbitrary found example)
In case of false result also check one segment end with point in polygon test
If you expect that "inside" case is more frequent - do "point in polygon" first.
Perhaps similar functions already exist in your framework.
Also note that there are simpler methods for axis-aligned rectangle (box)
Obtain the implicit equation of the line of support of your segment (as you say that "inside" is possible, your "line" must be a segment). It has the form
s(x, y) = a x + b y + c = 0
and S is positive on one side of the line and negative on the other side.
Now take every polygon side in turn and plug the coordinates of the two vertices. If the S changes sign between the vertices, the side intersects the line.
Now the trick is to use the parametric equation of the line from one endpoint to the other and find the intersection with the line in terms of the parameter t along the line. Note that the segment will correspond to the t interval [0, 1].
After scanning the whole polygon, you will have a list of t values. If the list is empty, no intersection. If all values in the list are <0 or >1, no intersection. Otherwise, there is an intersection (one subsegment or more).

How to traverse an array of latitude and longitude in JavaScript in an order?

I have an array of point like
aa = [ [1,2], [1,2],[2,1], [2,2], [3,1], [3,2] ]
How can I traverse through those point in an order. Fiddle here:
jsFiddle Link
I took some idea from Sort latitude and longitude coordinates into clockwise ordered quadrilateral but didn't work out
update: I think it would make sense if we add more description like traverse from A to F, with east to west direction, like shown in fig below. With this case I think we could sort the following way (noted in fig)
If you read the answer carefully, they admit that it's not an optimal path. It's simply following an arc from the selected point, and selecting in order anything that lies between the arc and the point. So imagine a pendulum swinging, and anything the bar of the pendulum touches is selected in that order.
This is not a quadrilateral path.
To make a quadrilateral path it may work if instead of calling the method from point A to all other points, you call it recursively selecting only the first point.
Basically, if instead of going from point A to all points, you use the algorithm in recursion, and after the first point is selected, you call it again with the new point. So each point is the clockwise most away from the previous point. Then after every call, you remove the selected points from the list of available points.
However, that will only work if the problem is simple. Meaning you won't have to indent your shape to select all points. So if you have points that is within the interior of a shape of outermost points, the solution will be drastically more complex.
It would require picking a point of indent, and then reversing the algorithm. Then doing that recursively.
I'd recommend ordering the points first.
Take the smallest as a point of reference then use the distance from the reference to sort.
var upper = upperLeft(points);
points.sort(function (point) {
return -point.distance(upper);
});
console.log(points);
This will invert them in sequence.
Remove the - sign to start from F to A

Determine if a 2D point is within a quadrilateral

I'm working on a JS program which I need to have determine if points are within four corners in a coordinate system.
Could somebody point me in the direction of an answer?
I'm looking at what I think is called a convex quadrilateral. That is, four pretty randomly chosen corner positions with all angles smaller than 180°.
Thanks.
There are two relatively simple approaches. The first approach is to draw a ray from the point to "infinity" (actually, to any point outside the polygon) and count how many sides of the polygon the ray intersects. The point is inside the polygon if and only if the count is odd.
The second approach is to go around the polygon in order and for every pair of vertices vi and vi+1 (wrapping around to the first vertex if necessary), compute the quantity (x - xi) * (yi+1 - yi) - (xi+1 - xi) * (y - yi). If these quantities all have the same sign, the point is inside the polygon. (These quantities are the Z component of the cross product of the vectors (vi+1 - vi) and (p - vi). The condition that they all have the same sign is the same as the condition that p is on the same side (left or right) of every edge.)
Both approaches need to deal with the case that the point is exactly on an edge or on a vertex. You first need to decide whether you want to count such points as being inside the polygon or not. Then you need to adjust the tests accordingly. Be aware that slight numerical rounding errors can give a false answer either way. It's just something you'll have to live with.
Since you have a convex quadrilateral, there's another approach. Pick any three vertices and compute the barycentric coordinates of the point and of the fourth vertex with respect to the triangle formed by the three chosen vertices. If the barycentric coordinates of the point are all positive and all less than the barycentric coordinates of the fourth vertex, then the point is inside the quadrilateral.
P.S. Just found a nice page here that lists quite a number of strategies. Some of them are very interesting.
You need to use winding, or the ray trace method.
With winding, you can determine whether any point is inside any shape built with line segments.
Basically, you take the cross product of each line segment with the point, then add up all the results. That's the way I did it to decide if a star was in a constellation, given a set of constellation lines. I can see that there are other ways..
http://en.wikipedia.org/wiki/Point_in_polygon
There must be some code for this in a few places.
It is MUCH easier to see if a point lies within a triangle.
Any quadrilateral can be divided into two triangles.
If the point is in any of the two triangles that comprise the quadrilateral, then the point is inside the quadrilateral.

Efficiently ordering line segments into a loop

I'm using a library (JavaScript-Voronoi) which produces an array of line segments that represent a closed polygon. These segments appear unordered, both the order in which the segments appear as well as the ordering of the points for each end of the segment.
(Edit: As noted in a comment below, I was wrong: the segments from the library are well-ordered. However, the question stands as written: let's assume that the segments do not have any ordering, as this makes it more generally useful.)
For example:
var p1 = {x:13.6,y:13.1}, p2 = {x:37.2,y:35.8}, p3 = {x:99.9,y:14.6},
p4 = {x:99.9,y:45.5}, p5 = {x:33.7,y:66.7};
var segments = [
{ va:p1, vb:p2 },
{ va:p3, vb:p4 },
{ va:p5, vb:p4 },
{ va:p3, vb:p2 },
{ va:p1, vb:p5 } ];
Notice how the first segment links to the last (they share a common point), and to the next-to-last. It is guaranteed that every segment shares an end with exactly one other segment.
I would like to convert this into a list of points to generate a proper SVG polygon:
console.log( orderedPoints(segments) );
// [
// {"x":33.7,"y":66.7},
// {"x":13.6,"y":13.1},
// {"x":37.2,"y":35.8},
// {"x":99.9,"y":14.6},
// {"x":99.9,"y":45.5}
// ]
It doesn't matter whether the points are in clockwise or counter-clockwise order.
The following code is what I've come up with, but in the worst-case scenario it will take n^2+n point comparisons. Is there a more efficient algorithm for joining all these together?
function orderedPoints(segs){
segs = segs.concat(); // make a mutable copy
var seg = segs.pop(), pts = [seg.va], link = seg.vb;
for (var ct=segs.length;ct--;){
for (var i=segs.length;i--;){
if (segs[i].va==link){
seg = segs.splice(i,1)[0]; pts.push(seg.va); link = seg.vb;
break;
}else if (segs[i].vb==link){
seg = segs.splice(i,1)[0]; pts.push(seg.vb); link = seg.va;
break;
}
}
}
return pts;
}
If your polygon is convex, you can pick middle point of each line segment, then use convex hull algorithm to find convex polygon by middle items, after that, because you know what is the arrangement of middles and also you know which middle belongs to which segment, you can find an arrangement in original array.
If you just want to find a convex hull, use convex hull algorithm directly, it's O(n log n), which is fast enough, but also you can find a Quickhull algorithm in javascript here. quickhull is also in O(n logn), but in average, the worst case is O(n^2), but it's fast because of less constant factor.
but in the case of general algorithm:
Set one end of each segment as First, and another end as second (randomly).
Sort your segments by their first x and put it in array First after that in array first sort segments with same first x by their first y and put two extra int into your structure to save start and end position of items with same first x.
Then again sort your segments with the second x value, .... and make array second.
Above actions both are in O(n log n).
Now pick first segment in array First, search for its second x value in both arrays First and second, in the case you find similar values, search for their y values in related subarray (you have start and end position of items with same x). You know there is only one segment with this order (also is not current segment), so finding next segment takes O(log n) and because in all there is n-1 next segment it takes O(n logn) (also preprocessing), which is extremely faster than O(n^2).
It should be possible to turn the points into a (double, unordered?) linked list in linear time:
for (var i=0; i<segments.length; i++) {
var a = segments[i].va,
b = segments[i].vb;
// nexts being the two adjacent points (in unknown order)
if (a.nexts) a.nexts.push(b); else a.nexts = [b];
if (b.nexts) b.nexts.push(a); else b.nexts = [a];
}
Now you can iterate it to build the array:
var prev = segments[0].va,
start = segments[0].vb, // start somewhere, in some direction
points = [],
cur = start;
do {
points.push(cur);
var nexts = cur.nexts,
next = nexts[0] == prev ? nexts[1] : nexts[0];
delete cur.nexts; // un-modify the object
prev = cur;
cur = next;
} while (cur && cur != start)
return points;
If you do not want to modify the objects, an EcmaScript6 Map (with object keys) would come in handy. As a workaround, you could use a JSON serialisation of your point coordinates as keys of a normal object, however you are then limited to polygons that do not contain a coordinate twice. Or just use the unique voronoiId property that your library adds to the vertices for identifying them.
For a convex polygon, you don't even need to know the side segments. You just need a bunch of vertices. The procedure to order the vertices is pretty simple.
average all the vertices together to get a point inside the polygon. note that this doesn't even need to be the centroid. it just needs to be a point inside the polygon. call this point C.
for each vertex V[i], compute the angle the line segment from V[i] to C forms with the line segment from V[i] to V[i]+(1,0). call this a[i].
sort the angles of vertices using the vertices as satellite data.
the sorted vertices are in order around the polygon. there are some redundancies that you can remove. 1 runs in linear time, 2 runs in linear time, 3 runs in n log n.

Categories

Resources