Intersect and Trim lines with a polygon - algorithm

I have defined a Polygon. I want to intersect and trim a list of other Lines with the Edges of this polygon (white rectangle here), so that endpoints of lines are limited to the inner part of the polygon.
currently, I'm intersecting each cyan line with the edges of the polygon which gives me the intersection points. But the problems is I don't know how to trim them. I know that I need to change the X1, Y1, X2 and Y2 of each intersecting line (cyan line) to the intersection point. But I don't know how do do it.
Let me explain it this way. A cyan line intersects one of the edges of the polygon, now I need to move the endpoint of the cyan line to the intersection point to simulate a trim right? Which endpoint I need to move? I'm a bit lost here.
public class Polygon
{
public List<Line>() Edges;
}
public class Line
{
public double X1;
public double X2;
public double Y1;
public double Y2;
}
var listOfIntersectingLines = new List<Line>() {L1, L2, ... };
var ListOfLinesLimitedToPolygon = ?

When you intersect two sections, that dont have an intersection point, your function should return null. For example: in your first picture, the 4th line from the bottom does not intersect the left or the top edge of the rectangle, it only intersects the bottom and the right edges. If you pick a cyan line, and intersect it with all edges of the polygon, you will always get either 2 or 0 intersection points. If you got 2, then those 2 points are the endpoints of your trimmed cyan line. If you got 0, that means the cyan line is outside of the polygon.
Possible problems:
1. An edge overlaps with a cyan line. You must decide whether you want to keep this line or not, and adjust you intersection function accordingly.
2. An edge goes through a corner. The easiest way to handle it is to return an intersect point if the line goes to the "first" endpoint of your edge, but return null if it crosses the 2nd endpoint. As your polygon is probably defined from point to point, it ensure that at every corner, there is only 1 edge that can be intersected.

Related

how can I find a shortest line (2 end points will be fine) from a group of points which is intersect with another given line segment

Say I got a bunch of points(red points) and a blue line segment, i want to find a line(2 points) which is intersect with the blue line segment and the sum of two end points' perpendicular distance to the blue line segment is the shortest distance .
P in this picture above is CD and the blue line segment intersect point.
I only know that they should be on the blue line's different side (left/right or above/below).
But there are still serveral variants can make this go south.Like AB and CE in this picture.
Edit : At first i thought i only need to make sure both of two end points' projection point lies on the blue line segment.But if I do so,there might be not so many good points for this case.I might just throw the only solution away.
Edit2 : The background is about image processing.Find 2 reliable points (say line M) near given line segment say L,if they intersect with each other then in another image they still does.It's about find line L's candidates in another image.
Edit3 :
Some python codes,but it's just my first thought.
It's not finished so it's not tested yet.
class Point:
def __init__(self):
self.point = (0, 0)
self.dist = float(Inf)
def update(self, point, dist):
self.point = point
self.dist = dist
for l0 in lines0:
# contains shortest perpendicular distance point on each side
temp = [Point(), Point()]
for p0 in points0:
x1, y1, x2, y2 = l[0]
# define given line L
line = lsrl.Line(lsrl.Point(x1, y1),
lsrl.Point(x2, y2))
# define point from points
point = lsrl.Point(p0[0], p0[1])
# perpendicular distance
dist = lsrl.distToLine(line, point)
# which side on return 0,1,2
side = lsrl.determineSide(line, point)
# lies on the given line
if side == 2:
pass
if dist < temp[side].dist:
# meet a better point then update
temp[side].update(p0, dist)
Sketch of algorithm:
Calculate all perp. distances including orientation (left or right of dividing line L).
Devide points into two lists (left or right).
Sort both lists by perp. distance.
Now build pairs from both lists, sorted by minimal sum of perp. distance.
Choose the first (smallest sum) pair with a connecting line that intersects L as result.

How to distinguish internal and external face of polygon

So I have a set of points making up a simple polygon
points = [(x0, y0), (x1, y1), ..., (xn, yn)]
The polygon may be concave or convex, both cases must be handled.
Next I create two arcs for each line by treating the arc between point A-B as different from the arc between point B-A. Next I create paths from these points by always choosing the closest counter-clockwise arc. So one path goes clockwise and one counter-clockwise: [(x0, y0), (x1, y1), ... , (xn, yn)] and [(xn, yn), (xn-1, yn-1), ... , (x0, y0)]
By traversing these arcs how do I know if the arcs are creating an internal face or an external face?
For example, in the two polygons below the same orange line is used on two different polygons. In the first polygon the top orange arc is in the internal face (pointing inwards) while in the other polygon the top orange arc is in the external face (pointing outwards).
My question arose from the answer by #HEKTO in this post: How to find all the polygonal shapes of given the vertices?.
Use Green's theorem. Iterate over the points and compute the integral, then check the sign. Like this:
decimal sum = 0.0;
for(int current = 0; current < points.length; current++)
{
int next = current + 1;
if (next == points.length)
next = 0;
sum += (points[this].y + point[next].y) * (point[next].x - point[this].x);
}
Check the sign of sum to find out whether the winding is clockwise or counter-clockwise. Which is which will depend on which direction the Y axis increases in.
Note that if you were trying to compute the area of the polygon you would multiply the Y part of the equation by 0.5, but since you're only interested in the sign of the result you don't need to.

Perimeter around a 2D grid-shape

Given a 2D grid of square cells of the form grid[x,y], I would like an algorithm that produces an ordered set of points that form the perimeter of the shape. In other words, the algorithm would produce a perimeter route around the corners of the shape as shown in this image:
.
I have looked at posts like this (where I got the above image), and I can find the corners of the shape. I have two questions: 1) once I have found the corners of the shape, how would I iterate over them in order to find a correct (and valid) route? 2) Would such a method to find the route consistently produce clockwise/counterclockwise routes? It does not matter to me that order of the vertices is clockwise/counterclockwise, only that they are consistently either clockwise or counterclockwise.
Thanks for any help
This assumes that any single corner won't be visited more than once per circuit. in other words, no corners where there are two grey and two black with the two grey squares in non adjacent corners.
Get your corners in some data structures that let you quickly :
get a list of all corners with a given x coordinate ordered by y coordinate.
get a list of all corners with a given y coordinate ordered by x coordinate.
Here's the algorithm:
Start with arbitrary corner c.
We'll say it has 3 adjacent black squares and 1 grey, and that the
1 grey square is in the -x,+y direction.
Choose perimeter direction. We'll say clockwise.
Determine which direction the perimeter goes in that corner. This can be done
by looking at the direction of the adjacent tile there's only 1 color of.
In our example, the perimeter goes -x/+y
Determine if c is concave or convex.
Convex has 3 adjacent black squares, concave has 3 adjacent grey squares.
In our example, c is convex because it has 3 adjacent black squares.
Knowing the direction of the perimeter from that corner and if it's concave or
not tells us what direction is clockwise:
clockwise at convex +x/-y is +x,
clockwise at convex +x/+y is +y,
clockwise at convex -x/-y is -y,
clockwise at convex -x/+y is -x
If it is concave clockwise goes the other direction.
(obviously if the desired perimeter direction is counterclockwise, it's the opposite)
Because c in our example is a convex corner and it goes -x/+y,
that means clockwise is along the x wall, so set current_axis = x,
It goes negative in that direction so set current_direction = -1
Otherwise, it would be set to 1
create list ordered_corner_list that only contains c
While length of ordered_corner_list < number of corners:
Get list of all corners with same value of current_axis as c ordered by the other axis.
e.g. for the first iteration, get same x value as c ordered by y
if current_direction = -1:
find node with the next lowest ordered value from c.
e.g. for the first iter, get corner with next lowest x from c
else:
find node with the next highest ordered value from c
assign that node to c
append c to ordered_corner_list
set current_axis = the other axis
e.g. for the first iteration, current_axis = y here
set current_direction to the direction that corner goes in the current_axis

Shift point into rectangle by shortest distance

Given a rectangle defined by 4 points is there an algorithm to shift a point so that it lies inside the rectangle moving it the shortest distance.
I should have clarified the target rectangle has an arbitrary rotation. Also I am not so concerned with the translation vector I simply want to know which point within a arbitrary rectangle is closest to said point
The shortest distance to move the point to the rectangle will either move the point to one of the corners or one of the sides (assuming the point isn't already inside the rectangle which you could test for like a bounding box). So what you want to do is find the distance from the point to each of the segments representing the sides. This is a point-segment distance and there are lots of places to find examples online.
Here's a clean example that only returns distance, but I've highlighted the three geometric cases of 1. Nearest to first point on segment 2. Nearest to second point on segment 3. Nearest to the side.
float dist_Point_to_Segment( Point P, Segment S)
{
Vector v = S.P1 - S.P0;
Vector w = P - S.P0;
double c1 = dot(w,v); // Point is closest to first point on segment
if ( c1 <= 0 )
return distance(P, S.P0);
double c2 = dot(v,v); // Point is closest to second point on segment
if ( c2 <= c1 )
return distance(P, S.P1);
double b = c1 / c2; // Point is closest to a side
Point Pb = S.P0 + b * v;
return distance(P, Pb);
}
So you just have to do the above for each of the four sides of the rectangle. You'll want to identify which case (1, 2, or 3) gave you the closest point. That will give you the translation vector to the rectangle.
I should mention, there are optimizations you can make if you want to speed up your implementation. For example, if you test two adjacent sides and you find that the closest point for both is the same vertex, then you can stop there because that must be the closest point on the rectangle to the point.

How to identify the boundary points of area overlapped between 2 rectangles in 2D?

I'm looking to return the coordinates of the points bounding the area of overlap between 2 arbitrary rectangles in 2D. Whats the best way to approach this that would take care of all the special cases eg:
Rectangles intersecting only on a single vertex ? (the program would have to return the lone vertex)
Rectangles which share whole or part of a side ? (the program would have to return the endpoints of the common line segment)
To add to the complexity, it has to order the points in either clockwise/anticlockwise order. As such, I can use a convex hull algorithm to order them before reporting, but if there's an algorithm that can figure out the bounding points in order directly, that'll be the best !!
Any ideas of what avenues I should be looking at ? I'm not looking for code projects etc, only a general idea of a generic algorithm for which I don't have to keep a lot of
if "special case" then "do this" kind of code.
EDIT: The rectangles are arbitrary - i.e. they may/may not be parallel to X/Y axis...
Just use the general convex polygon intersection method. Look up intersect convex polygons rotating calipers.
Alright, we'll try this again...
Consider a union of the two, made up of areas defined by drawing a line from every vertex in ABCD (in black) to EFGH (in red):
The hard part here is coming up with all of the shapes defined by these lines (both the gray lines and the original lines coming from the ABCD and EFGH rectangles.)
Once you figure that out, create a linked list of these shapes, and assume every one of these shapes exists within the intersection.
Step 1. Translate & rotate everything so that ABCD has one vertex on 0,0 and its lines are parallel/perpendicular to the x and y axes.
Step 1A. Find the lowest y-value vertex in ABCD, and then subtract it from all other verts in the scene. Let's assume for the purposes of demonstration that that vertex is C. By subtracting C from every vertex in the scene, we will effectively move the origin (0,0) to C, making rotation around C easy.
for all shapes in linked list {
for all vertices in shape {
vertex -= C;
}
}
Step 1B. Rotate everything about the origin by an angle equal to the angle between the C->B vector and the x-axis, so that B lands on the x-axis:
// see http://en.wikipedia.org/wiki/Atan2
float rotRadians = atan2(B.x, B.y); // assuming ABCD vertices are labelled clockwise
for all shapes in linked list {
for all vertices in shape {
rot(thisVert, rotRadians);
}
}
// ...
// function declaration
void rot(theVertex, theta) {
tempX = theVertex.x;
tempY = theVertex.y;
theVertex.x = cos(theta) * tempX + sin(theta) * tempY;
theVertex.y = cos(theta) * tempY - sin(theta) * tempX;
}
If ABCD vertices were labelled clockwise, the ABCD vertices should now look like this:
A = ABCDx , ABCDy
B = ABCDx , 0
C = 0 , 0
D = 0 , ABCDy
(If they were not labeled clockwise, then the "lies within" check in Step 2 won't work, so make sure the vert used in the atan2(...) call is the vertex counterclockwise from the lowest vertex.)
Step 2. Now we can easily analyze whether or not a shape lies within the ABCD rectangle, e.g. if (thisVert.x >= 0 && thisVert.y >= 0 && thisVert.x <= ABCDx && thisVert.y <= ABCDy). Traverse the linked list of shapes, and check to make sure each vertex of each shape lies within ABCD. If one vertex of a shape does not lie within ABCD, then that shape is not part of the ABCD/EFGH intersection. Mark it as not part of the intersection and skip to the next shape.
Step 3. Undo the rotation from Step 1B, then undo the translation from Step 1A.
Step 4. Repeat Steps 1-3 with EFGH instead of ABCD, and you will have your intersection set.
If the only intersection between the two sets is a line, then the above will return nothing as an intersection. If the intersection == NULL, then check for lines that intersect.
If the intersection is still NULL, then check for intersecting points.
This is probably really rough but:
object rectangle {
pos { x, y } // top-left position
size { height, width } // rectangle-size
}
collision::check (rectangle rect) {
// collision-detection logic
collision->order_coords(coords); // order-coords clockwise;
return collision_result_object; // return collided vertices, ordered clockwise, or 0 if rect hit nothing
}
collision::order_rects (rectangle *rect, opt angle) {
return clockwise_rects; // returns rectangles ordered clockwise
}
collision::order_coords (coordinate *coord, opt angle) {
return ordered_coords; // recieves coordinates and returns ordered clockwise
}
rectangle rects; // bunch of rectangles
ordered_rects = collision->order_rects (rects); // order rects starting at 12PM
loop {
foreach ordered_rects as i {
if (collision->check(i)) {
array_of_collision_result_objects[i] = collision->check(i); // start checking rects starting at 12PM, if collision found, return ordered vertexes
}
}
}
Find all the intersections of segments of rectangles. The result consists of some of them and some of initial vertices. To find them just check for every point it lies in both rectangles. Remove unnecessary points (if there are 3 or more on one line). The result is convex and no point you get is strictly inside it, so (if there are at least 3 of them) sort points from some inner point by angle and enjoy the result.
I've come up with a reasonable method that should cover all possible cases:
All we need is basically 3 steps :
Step 1:
for each side Si of R1
for each side Sj of R2
Check if Si and Sj intersect. If they do, push the point in results array
(This also has to take care of the case in case Si and Sj overlap, which is
basically checking if they have the same equation or not - if so, push in
the points of overlap. This also takes care of the case where a vertex of
R2 lies on Si).
next
next
Step 2:
for each vertex Vi of R1
Check if Vi lies inside R2, If so, push it in the results array.
next
Step 3:
for each vertex Vi of R2
Check if Vi lies inside R1, If so, push it in the results array.
next
Now, order the results array, and return
For step 2 & 3 (how to find if a point lies inside a rectangle) - I'd use this excellent article (the last algorithm stated there).

Resources