Is there a simple algorithm that finds a separating line between two polygons such that they lie on either side of the line? Or preferably does anyone know of a library that does this sort of thing? Any help would be appreciated
EDIT:
My solution:
I used JTS: http://www.vividsolutions.com/jts/JTSHome.htm
Created two Polygons using this library and ran DistanceOp to find the two nearest points between the polygons (not necessarily vertices). Then simply calculated a perpendicular line to the line that connects them.
Let A and B be your two polygons. First find the convex hull of each, C(A) and C(B).
Clearly a line that separates A from B also separates C(A) from C(B).
Let a be a point on C(A) and b a point on C(B). One can walk a and b around
the boundaries until a separating line through a and b is found. This can be
accomplished in linear time, but I will not describe that now.
Let's say you have a polygon A with points A1,A2,A3,...,AN and a polygon B with points B1,B2,B3,...,BM.
What you could do is to describe a line from the point AX to BX for every possible combination (A1 & B1, A1 & B2, ... AN & BM).
Such line could be described in the parametric format: SomePoint = InicialPoint + Direction * t and will be a possible candidate to a "separating-line". Keep it!
Now what you gotta do is to DESCRIBE ANOTHER vector from each point of each polygon to this candidate line. Each of those lines will have it's direction vector.
If the cross product of the direction vector of each line with the candidate's direction vector have the same direction (Z-positive or Z-negative), it means those points are in the same side of the separating line (still candidate).
Now check for all lines you described for each point of each polygon. You can figure out if all points of polygon A are in one side and all points in the polygon B are in the other side... then you found the line you want. If not, you gotta try a next candidate line (AX-BX). If you don't find any of these combination with all possible candidate lines, it means you have an intersection between the polygons.
I am not sure if it's the best/fastest algorithm but I'm sure it works.
Related
I'm trying to find an efficient algorithm that can check if a line between two vertices in a simple (edit: simple concave) polygon contains points that lie outside the domain of the polygon. The closest question I could find is this one: https://stackoverflow.com/a/36378838/12135804
But I'm not sure the answer is quite right. It might be, in which case if someone could clarify that would be great.
The basic idea is illustrated in the below picture:
Where I would like the red line to fail and the green line to succeed. I know one can't naively test the midpoint as that wont work in every case, but finding any point on the line outside the polygon's domain should disqualify it.
I appreciate any and all help!
Edit: Forgot to include cross-post link to mathematics stack exchange:
https://math.stackexchange.com/q/4040059/892519
Let's assume that the topmost point is A and the others are named B, C ... counter-clockwise, so we know what we're talking about.
If you take the red segment B-D, the one point in between is on the left. If you take the green segment D-F, the one point in between is on the right. Now, a more interesting segment would be B-E, where C is on the left while D is on the right.
In order to determine left and right, use the vector product. The length depends on the sin function, so if you get a value less than zero it's one side and more than zero is the other side.
After a lot of googling, I finally found this answer to a stackoverflow question from ~12 years ago: https://stackoverflow.com/a/693877/12135804
Assuming the edges in the polygon follow a certain order, a simple ccw test can be created using a line's starting point (p), the next ccw point in the polygon from that starting point as an inflection point (q), and the endpoint of the line (r). For the red line BD, the test would check if B,C,D is ccw (it's not). For the green line DF, test if D,E,F is ccw (it is!). This would work even if the points are non-consecutive. However, this would fail when the order of the red-green lines is reversed. For instance, if the red line became DB, the test would check D,E,B, which would pass the ccw test.
I think a more robust solution is to search for the pair of two edges in the concave polygon that share the endpoints of the line to test. For both pairs, calculate the angle between the two edges to the x-axis. Calculate the angle of the line to the x-axis as well. If the line is within the polygon, the line's angle should lie between the max and min of the polygon edges' angles for both endpoints.
Whether to test the obtuse or acute range of angles depends on some factors, I think. The red line's angle at B w.r.t. to the x axis would be in the obtuse bound between AB and BC, and the same is true at point C. Visually, it's plain to see the acute bound is what needs to be used for the max/min test at both points. If the baseline to compute the bounds from can be chosen logically, then it can be done.
Of course, this doesn't work if the line crosses outside the polygon on the way between both endpoints, but this does handle the degenerate case for a normal line-polygon intersection test. Assuming it works in every degenerate case, that is.
I won't mark this an answer because I can't prove it.
Edit: Well, I came back to thinking about this again and decided to search for questions similar to the angular bounding I posed above, and found this: https://stackoverflow.com/a/17497339/12135804
This answer satisfies not knowing the orientation of the lines! However, it assumes the minimum bound between A and B should be tested. This doesn't work for concave vertices, when AxB is < 0. In this case, a line attached to the vertex shared by lines A and B will return true if it's pointing outside the polygon, and conversely false if it's inside. I think flipping the result based on the sign of AxB should be enough to account for this, though. (a hunch that is verified in this related answer: https://stackoverflow.com/a/43384516/12135804)
I'm facing the following problem: I'm given a set of coordinates on an integer grid that define the vertices of a polygon. The polygon is guaranteed to be convex. It's proven that such a polygon can always be cut into 4 equal area parts by 2 orthogonal lines. Let's call the point of these lines' intersection P.
Given that set, I should calculate the coordinates of P within the polygon and the angle the lines need to be turned on so that the lines cut the polygon into 4 equal parts.
I realise that, put generally, the cake cutting problem has no "good" solution. But this particular case of it should.
I've searched for an algorithm to solve that problem, but found nothing useful.
Where should I look?
My approach would be to calculate the coordinates of the centre of the polygon (that can be done more or less easily), place Pthere and then "wiggle" the lines until the areas of the parts match. But that sounds too inelegant.
UPD: that's the problem I'm dealing with. Perhaps this question should be suspended until I come up with actual code questions.
Here is a partial sketch of the solution:
Choose an arbitrary direction and find the line parallel to that direction that splits the polygon in two. To achieve this, draw a line by every vertex to decompose the polygon in slabs. The respective areas of the slabs will tell you what slab the desired line intersects. Simple linear interpolation will give the exact location of the line.
Now your polygon is split in two convex polygons. For each halve, repeat the above procedure using the perpendicular direction. In general, you will get two distinct splitters, and what remains to be done is to find the direction such that they do coincide.
In the given direction, the splitters intersect four specific edges of the polygon. If you slightly rotate, they still intersect the same four edges. You can decompose a full turn in angular ranges such that the four intersected edges remain the same.
Knowing the four intersected edges, you can establish the relation that tells you the distance between the two perpendicular splitters as a function of the angle. Then you can compute the angle at which the two splitters coincide, and check if this angle belongs to the range defined for these edges.
By trying all ranges in turn, you will find the solution.
Note: the limits of the angular ranges correspond to directions parallel or perpendicular to the lines joining two vertexes.
Please take a look at pic1 above first.
2 points combine a line, let's call it LineAB, and we can get a normal from our eye sight direction, let's call it view-direction, vector(lineAB) X view-direction, we can get a normal named plane-normal. in the pic1, plane-normal is directed to the top (green arrow), and the plane with plane-normal cut the map into 2 parts.
As the point C is on the same direction of the plane-normal, we regard it as inside, let's return true. Point D is on the anti-direction of plane-normal, it is outside, return false.
My problem is in the pic2 as following:
Now, there are many points A,A1,A2...A5,... An, build many lines such as lineAA1, line A1A2, ... LineAn-1An (one condition is: every angle between 2 adjacent lines are equal to or more than 90 degree) and plus with view direction (the direction from our eye sight), we can get many planes PAA1, PA1P2, ... PAn-1An which also cut the map to 2 parts.
I need to check one point is inside or outside.
for example, point C is inside but point D is outside.
Regarding one plane separating the dim(3)-space isn't difficult, to consider a piecewise assembled dim(2)-plane we need to dive deeper:
The problem may be reduced to separating the dim(2)-space.
If only for the calculation of the normal the 3rd dimension is considered, then that can solved in a different way:
Let v = (a,b) be the vector of a lineAB. The normal is (b, -a) or (-b, a) respectively.
If you want to check only if a point is within a polygon, just use the ray-casting-algorithm.
When it comes to dividing the dim(2)-space into two separate spaced by your polygonal chain, it won't be enough to check if the point is on the positive directon of the normals on each part line(A[i-1])(A[i]):
Polygonal chain
Point P is positive with respect to normal N0, but negative w.r.t. normal N1.
Also, the upper angles are all above 90° (some counter angles are also displayed), but the polygon chain isn't convex either w.r.t. the upward y-axis.
To solve your issue, you can use the ray-casting-algorithm, going towards negative y-direction, i.e. "downwards", and see if the amount of intersections is odd.
If the line ends at a higher x-coordinate than the start point, an odd amount of intersections means "true"
If the line ends at a lower x-coordinate than the start point, an odd amount of intersections means "false"
You can find if a ray from point C (with view direction) intersects with one of the segments AiAi+1. It could be done with binary search by X-coordinate (to find potential segment quickly)
As shown in this image:
I have a set of line segments. I want to check which line-segments intersect with the perpendicular line drawn from a given point (x0,y0).
(E.g.: AB passes the check and BC does not.)
The only information I've got is two points of the line-segment, (x1,y1), (x2,y2), and the target point (x0,y0).
Is it possible to derive a simple formula using these three points?
Thanks in advance.
umanga
As background, if you need to, you can read up on dot product, its geometric interpretation, and in particular scalar projection.
Define the vectors v0=(x0,y0)-(x1,y1) and v2=(x2,y2)-(x1,y1).
Then the intersection point is
(x1,y1) + ((v0⋅v2)/(v2⋅v2))v2
The intersection point will be on the line segment if the scalar value (v0⋅v2)/(v2⋅v2) is between 0 and 1.
For a line AB and a point X, both angles, ABX and BAX must be acute (or right).
How to find the minimum perpendicular distance of point from a line in 3D plane?
Please give me the logic and I will try to code on myself.
Please let me know how to do it in terms of x,y,z that is in terms of coordinate systems.
I am finding it a bit difficult to find the right solution which will be easy from a coding point of view. Online solutions are little bit rusty to understand. So please help me.
Please note line is given in terms of 3D space equation.
Given point A and a line, pick two different points on the line (B and C). Calculate the area of the triangle ABC with use of Heron's formula. Multiply the area by 2 and divide it by length of [BC]. You have the result you needed.
For an infinite line, the minimum distance is the length of line segment at right-angles to the infinite line passing through the point starting at the line and ending at the point. The direction of the perpendicular is given by the cross product of the unit normal to the plane and the unit vector along the line, the foot of the perpendicular is given by simultaneous solution of the equation for the first line, and for the perpendicular through the point. The distance between the points is what you are after.
For a finite line, this is a solution only if the foot of the perpendicular is on the segment; otherwise it's the shorter of the distance between the point and either end of the segment.
You say the line is given as an equation in 3D, but really planes are given by equations. And since the line is said to be lying in a 3D plane, presumably given by another equation, the line is actually the intersection of two planes.
To get the direction vector of the line, take the cross product of the normals to the two planes. If you use Pavel's method, you don't need this.
To get a point on the line, pick some value for x, say x = 0. Then solve the two equations for y and z after plugging in that value. To find another point to use in Pavel's method, set x to some other value, say x = 1, and solve the system again.
If the line is oriented the wrong way (perpendicular to the x axis), x may be a fixed value. In that case, try setting y to two fixed values. If that still doesn't work, try z. Also, check that the original planes are not parallel, so that there actually is a line of intersection.
To solve the question without Pavel's method, cross the direction of the line with the vector formed by the given point and a point you found on the line. Now cross that result with the line direction to get a new vector. Dot that vector with the original point and again with a point on the line. Take the difference, and divide by the length of the vector.