Calculate intersection of two segments - algorithm

I have two segments. Every segment will be either vertical or horizontal (0°, 90°, 180°, 270°). I need to find intersection point of these two segments. I need also calculate the intersection point if both segments are vertical or horizontal. Thank you.

There are 2 point P1[(x1,y1),(x2,y2)] and P2[(x1,y1),(x2,y2)].
Since the lines are either horizontal or vertical, one line will have a x constant and the other has a y constant.
So for each point check if x1 = x2 and it true make x = x1. Similarly if y1=y2, make y = y2.
(x,y) is your intersection point.
If either x or y remains null at the end, then it means the lines are parallel hence no intersection. (If lines are parallel, the same variable will vary)

Related

Finding the length of 3 rectangles so that they share one corner to form a triangle, given a common width and 3 points

Hi sorry for the confusing title.
I'm trying to make a race track using points. I want to draw 3 rectangles which form my roads. However I don't want these rectangles to overlap, I want to leave an empty space between them to place my corners (triangles) meaning they only intersect at a single point. Since the roads have a common width I know the width of the rectangles.
I know the coordinates of the points A, B and C and therefore their length and the angles between them. From this I think I can say that the angles of the yellow triangle are the same as those of the outer triangle. From there I can work out the lengths of the sides of the blue triangles. However I don't know how to find the coordinates of the points of the blue triangles or the length of the sides of the yellow triangle and therefore the rectangles.
This is an X-Y problem (asking us how to accomplish X because you think it would help you solve a problem Y better solved another way), but luckily you gave us Y so I can just answer that.
What you should do is find the lines that are the edges of the roads, figure out where they intersect, and proceed to calculate everything else from that.
First, given 2 points P and Q, we can write down the line between them in parameterized form as f(t) = P + t(Q - P). Note that Q - P = v is the vector representing the direction of the line.
Second, given a vector v = (x_v, y_v) the vector (y_v, -x_v) is at right angles to it. Divide by its length sqrt(x_v**2 + y_v**2) and you have a unit vector at right angles to the first. Project P and Q a distance d along this vector, and you've got 2 points on a parallel line at distance d from your original line.
There are two such parallel lines. Given a point on the line and a point off of the line, the sign of the dot product of your normal vector with the vector between those two lines tells you whether you've found the parallel line on the same side as the other, or on the opposite side.
You just need to figure out where they intersect. But figuring out where lines P1 + t*v1 and P2 + s*v2 intersect can be done by setting up 2 equations in 2 variables and solving that. Which calculation you can carry out.
And now you have sufficient information to calculate the edges of the roads, which edges are inside, and every intersection in your diagram. Which lets you figure out anything else that you need.
Slightly different approach with a bit of trigonometry:
Define vectors
b = B - A
c = C - A
uB = Normalized(b)
uC = Normalized(c)
angle
Alpha = atan2(CrossProduct(b, c), DotProduct(b,c))
HalfA = Alpha / 2
HalfW = Width / 2
uB_Perp = (-uB.Y, ub.X) //unit vector, perpendicular to b
//now calculate points:
P1 = A + HalfW * (uB * ctg(HalfA) + uB_Perp) //outer blue triangle vertice
P2 = A + HalfW * (uB * ctg(HalfA) - uB_Perp) //inner blue triangle vertice, lies on bisector
(I did not consider extra case of too large width)

Fast algorithm for testing if every rectangle built using any two points from a list contains a third point from that list

The problem is as it follows:
Given N (N <= 100,000) points by their Cartesian coordinates, test if every rectangle (with an area > 0) built using any two of them contains at least another point from that list either inside the rectangle or on his margin.
I know the algorithm for O(N^2) time complexity. I want to find the solution for O(N * logN). Memory is not a problem.
When I say two points define a rectangle, I mean that those two points are in two of its opposite corners. The sides of the rectangles are parallel to the Cartesian axes.
Here are two examples:
N = 4
Points:
1 1
3 5
2 4
8 8
INCORRECT: (the rectangle (1, 1) - (2, 4) doesn't have any point inside of it or on its margin).
N = 3
Points:
10 9
13 9
10 8
CORRECT.
Sort the points in order of the max of their coordinate pairs, from lowest to highest (O(n*log(n))). Starting with the lower-left point (lowest max coordinate), if the next point in the ordering does not share either the original point's x-value or its y-value (e.g. (1,2) and (5,2) share a y-coordinate of 2, but (1,2) and (2, 1) have neither coordinate in common), the set of points fails the test. Otherwise, move to the next point. If you reach the final point in this way (O(n)), the set is valid. The algorithm overall is O(n*log(n)).
Explanation
Two points that share a coordinate value lie along a line parallel to one of the axes, so there is no rectangle drawn between them (since such a rectangle would have area=0).
For a given point p1, if the next "bigger" point in the ordering, p2, is directly vertical or horizontal from p1 (i.e. it shares a coordinate value), then all points to the upper-right of p2 form rectangles with p1 that include p2, so there are no rectangles in the set that have p1 as the lower-left corner and lack an internal point.
If, however, the next-bigger point is diagonal from p2, then the p1 <-> p2 rectangle has no points from the set inside it, so the set is invalid.
For every point P = (a, b) in the set, search the nearest points of the form Y = (x, b) and X = (a, y) such that x > a and y > b.
Then, find if the rectangle defined by the two points X, Y contains any* internal point R besides P, X and Y. If that is the case, it's easy to see that the rectangle P, R does not contain any other point in the set.
If no point in the set exists matching the restrictions for X or Y, then you have to use (a, ∞) or (∞, b) respectively instead.
The computational cost of the algorithm is O(NlogN):
Looking for X or Y can be done using binary search [O(logN)] over a presorted list [O(NlogN)].
Looking for R can be done using some spatial tree structure as a quadtree or a k-d tree [O(logN)].
*) If X, Y contains more than one internal point, R should be selected as the nearest to P.
Update: the algorithm above works for rectangles defined by its botton-left and upper-right corners. In order to make it work also for rectangles defined by its botton-right and upper-left corners, a new point X' (such that it is the nearest one to P of the form X' = (a, y') where y' < b) and the corresponding rectangle defined by X', Y should also be considered for every point in the set.

Traversing Line Segments

I have a question on this algorithmic problem; I'll paste the problem then go over my current thoughts and solution.
There are N (up to 100,000) line segments defined as [(x1, y1), (x2, y2)], where x1 < x2 and y1 < y2 (e.g. The line segments have positive slope). No line segments touch or intersect, even at endpoints. The first segment has (x1, y1) = (0, 0). Imagine each segment as a 2-D hill a person has to climb.
A person starts at (0, 0) and lands on the first hill. Whenever a person lands on a hill, he climbs to the end, which is (x2, y2) and jumps straight down. If he lands on another hill (anywhere on the segment), the process continues: he climbs that hill and jumps. If there are no more hills, he falls to -INFINITY and the process is over. Each hill (x1, y1) -> (x2, y2) should be
regarded as containing the point (x1, y1) but not containing the point (x2,
y2), so that the person will land on the hill if he falls on it from above at
a position with x = x1, but he will not land on the hill if he falls on
it from above at x = x2.
The objective is to count how many hills he touches.
My current thoughts
I'm thinking of sweeping a line across the plane along the x-axis. Each segment consists of a BEGIN and END event; everytime we encounter the beginning of a line segment, we add it into a set. Every time we encounter the ending of a line segment, we remove it from the set. And when we hit the END point of the current hill we are on, we should check the set for the highest hill that we can land on. However, I don't know how to determine how to check this quickly, because there could be potentially N entries inside the set. Also, after jumping on to another hill, the order of these will change because the slopes of each segment are probably different, and I don't know how to account for this difference.
Any thoughts?
In pre-processing you can traverse all segments and add points in an stl multimap< pair, linesegment> or something similar. Cost of this pre-processing would be O(NlogN). Then you can continue with your sweep line method. You need iterate points from multimap. Because all points are sorted, and contains reference to line the point corresponds to, it would cost O(N).
Barron, your algorithm is perfectly correct. The order of elements in your sorted list will not change as the sweep line moves, because if that happened you would have an intersection of line segments.
You just need a way to keep track of the sorted line segments. One way to do this would be to keep a map of line segments, in which the comparison operator compares line segments by the y value on the segment as calculated by the current x value of the current sweep location. Inserting, deleting, and querying from this map is O(log(n)).
Here's a rough direction in Haskell. "segments" are the line segments. (In this example, the third segment is slightly above the second segment in order to test the code.) "matches" finds the hills/segments that place the top of the last segment, pt (x0,y0), within their x bounds and above or equal to the y corresponding to their affine transformation of x0 ("affine" calculates the affine function for the segment -- the ax+b, so to speak). Finally, countHills tests the possible matches for the next hill and chooses the one with the closest y to y0 (calculated by the affine a*x0+b), and outputs the result, accumulating the hills climbed on in order. Clearly this idea may need optimization for much longer segment lists.
The result output below shows the first and third segments. The second hill/segment is not in the result because it is lower than the third - we land on the third instead:
*Main> countHills segments
[((0.0,0.0),(2.0,5.0)),((1.0,1.5),(5.0,3.0))]
import Data.List
segments = [((0,0),(2,5)),((1,1),(5,2)),((1,1.5),(5,3))]
top segment = snd segment
matches pt =
let x0 = fst pt
y0 = snd pt
in filter (\x -> x0 >= fst (fst x)
&& x0 < fst (snd x)
&& (affine x) x0 <= y0) segments
affine segment =
let x1 = fst $ fst segment
y1 = snd $ fst segment
x2 = fst $ snd segment
y2 = snd $ snd segment
in (+ ((x1*y2-x2*y1) / (x1-x2))) . (* ((y2-y1) / (x2-x1)))
countHills segments = countHills' (head segments) [] where
countHills' x result =
let hills = matches $ top x
x0 = fst (top x)
y0 = snd (top x)
in if null hills
then result ++ [x]
else let nextHill =
minimumBy (\a b -> compare
(y0 - (affine a) x0)
(y0 - (affine b) x0)) hills
in countHills' nextHill (result ++ [x])
I think a line sweep algorithm is a good idea here. Let me summarize your algorithm so far and add my improvements:
You are sweeping a line from left to right.
You have an active list which lists all currently active segments.
These are segments intersecting with the sweepline
Every endpoint of every line segment is considered an 'event'
when the line sweeps across the 'start' of a segment, the segment gets added into the list of active segments
When the line sweeps across the 'end' of a segment, the segment gets removed from the list of active segments
If there are no line segments in the active set upon removal of a line segment, the process ends
If there are line segments in the active set upon removal of a line segment, we need to determine
A) Whether there are any line segments in the active set with portions 'below' the previously removed end vertex, and
B) Which of these line segments the person will land on.
The idea is to sort your line segments in the 'active set' such that this query is efficient. What I'm thinking is that if we know a line's slope and y intercept we can compute intersection points for a start vertex's x position
GreaterThan(segment1,segment2){ // is segment 1 higher than segment 2?
//y = mx + b; compute y value of point on segment 2 for a given x value from s1
//that is, m and b are slope and y-intercept of s2
yVal = m * (segment1.first.x) + b
if (yVal < segment1.first.y)
return true //the point on s2 corresponding to s1.first is lower than s1.first
return false
}
Because lines don't intersect, then you can assume no other line will 'go through and over' this line.
If we avoid adding any line segments whose start vertices are higher than the end vertex of our "person's" current line, then we should successfully avoid adding any extraneous line segments to the active set (i.e. line segments "above" our current one)
Now we just need to worry about the special case of the vertex of the last line segment not being 'landable'. Because vertices are events, we will process all events before we do our segment testing. this way, you will not accidentally land on the end vertex of a line in the active set, but you WILL land on a line segment that has just been added.
Now that we have a sorted list of line segments in the active set, we can query it in constant time to just get the top one, and adding a new one should only take logarithmic time.
How does this sound?

Finding shared volume of two overlapping cuboids

What is the most efficient way to find the shared space occupied by two overlapping cube objects?
I'm not necessarily looking for source code, just the general idea on how it should be solved.
To simplify, the algorithm doesn't have to take into account rotated cubes.
The overlap of two non-rotated cubes is still a 'box'. If two corner points of box A are (x,y,z) and (x',y',z') (x'>x,y'>y,z'>z) and two corner points of box B are (a,b,c) and (a',b',c') (a'>a,b'>b,c'>c) then the volume of the overlap is
max(min(a',x')-max(a,x),0)
* max(min(b',y')-max(b,y),0)
* max(min(c',z')-max(c,z),0)
How the read the formula:
The overlap starts on the X axis at the maximum of the two coordinates x and a and ends at the minimum of a' and x'. If a' < x (i.e. a < a' < x < x') then there's no overlap and what happens is that max(a,x) = x > min(a',x') = a', so the difference becomes negative and the volume is zero (hence the outer max(...,0)) term. The same applies for the other two axes.
If the cubes aren't rotated (axis aligned), the overlap of the dimensions is enough to describe the overlap of the cubes.
Consider the problem in 2 dimensions:
________
| S2 |
____|___ |
| | | |
| |___|____|
| S1 |
|________|
The overlapping area is described by a width of S1.xmax - S2.xmin, and a height of S1.ymax - S2.ymin. To determine the order of subtraction requires a couple of if tests. You may find there's no overlap at all. To do this for cubes, consider the z dimension in addition to x and y.
Compute the min/max in each dimension of each of your cubes and then test these against each other e.g. in the x direction where the cubes are labeled 1 and 2
XminInt;
if ( Xmin1 > Xmax2 )
{
// no intersection
}
else if ( Xmin1 >= Xmin2 )
{
// possible cube intersection
XminInt = Xmin1;
}
else if ( Xmin2 <= Xmax1 )
{
// possible cube intersection
XminInt = Xmin2;
}
Do something similar for the max and repeat both for y and z. If you hit the no intersection case in any of them then you can exit early. If you don't exit early in any of the six possible early exit clauses then you will have all six defining values for the intersection cube i.e. min/max for each dimension.
The six early returns are pretty much the simplest example there is of a separating axis method. Since your shapes are cubes and are axis-aligned the Cartesian axes are the possible separating axes. Testing is then a simple matter of comparing the min/max values as above.
Note that I have implemented the above method in C++ and confirmed that it works.
I have the same question and this is the best thread that comes up but the best answer does not address the question. After sometime, I have it solved. Antti answer calculates the volumne as a scalar rather than defining the overlapping cube points. Using his definition to define a cube, to get the shared space occupied by two overlapping cube objects, that shared cube is:
let box A be a vector (Ax,Ay,Az) and A' be (Ax',Ay',Az') with (Ax'>Ax,Ay'>Ay,Az'>Az)
let box B be a vector (Bx,By,Bz) and B' be (Bx',By',Bz') with (Bx'>Bx,By'>By,Bz'>Bz)
let box C be our new overlapping cube
then the intersection between the two cubes is:
C = Min(A', B');
C' = Max(A, B);
Note if the boxes touch only at a single point, then C = C'. If only one dimension is different, touches at a line, and if only 2 dimensions are different touches at a plane.

How to get the length of a segment crossing a square?

I have a line, defined by the parameters m, h, where
y = m*x + h
This line goes across a grid (i.e. pixels). For each square (a, b) of the grid (ie the square [a, a+1] x [b, b+1]), I want to determine if the given line crosses this square or not, and if so, what is the length of the segment in the square.
Eventually, I would like to be able to do this with multiple lines at once (ie m and h are vectors, matlab-style), but we can focus on the "simple" case for now.
I figured how to determine if the line crosses the square:
Compute the intersection of the line with the vertical lines x = a and x = a + 1, and the horizontal lines y = b and y = b + 1
Check if 2 of these 4 points are on the square boundaries (ie a <= x < a + 1 and b <= y < b + 1)
If two on these points are on the square, the line crosses it. Then, to compute the length, you simply subtract the two points, and use Pythagorean theorem.
My problem is more on the implementation side: how can I implement that nicely (especially when selecting which 2 points to subtract) ?
Let square be defined by corner points (a,b), (a+1,b), (a,b+1), (a+1,b+1).
Step 1: Check if the line intersects the square...
(a)Substitute each of the coordinates of the 4 corner points, in turn into y - mx - h. If the sign of this evaluation includes both positive and negative terms, go to step b. Otherwise, the line does not intersect the square.
(b)Now there are two sub-cases:
(b1)Case 1: In step (a) you had three points for which y - mx - h evaluated to one sign and the fourth point evaluated to the other sign. Let this 4th point be some (x*,y*). Then the points of intersection are (x*,mx*+h) and ((y*-h)/m,y*).
(b2)Case 2: In step (a) you had two points for which y - mx - h evaluate to one sign and the other two points evaluated to the other sign. Pick any two points that evaluated to the same sign, say (x*,y*) and (x*+1, y*). Then the intersection points are (x*, mx* + h) and (x*+1,m(x*+1) + h).
You would have to consider some degenerate cases where the line touches exactly one of the four corner points and the case where the line lies exactly on one side of the square.
Your proposed method may meet with problems in step (1) when m is 0 (when trying to compute the intersection with y = k).
if m is 0, then it's easy (the line segment length is either 1 or 0, depending on whether b <= h <= b+1).
Otherwise, you can find the intersections with x = a and a+1, say, y_a, y_{a+1} via a substitution. Then, clip y_a and y_{a+1} to between b and b+1 (say, y1 and y2, i.e. y1 = min(b+1, max(b, y_a)) and similarly for y2), and use the proportion abs((y1-y2)/m) * sqrt(m^2+1).
This makes use of the fact that the line segment between x=k and x=k+1 is sqrt(m^2+1), and the difference in y is m, and similarity.
You can do like this:
first find center of square and then find length of diagonal. If the distance from center of square to line is less than length of diagonal then the line will intersect the square. and once you know that line will intersect then you can easily find the intersected line segment. I think you are trying to make weight matrix for Algebraic reconstruction technique. I hope this is correct answer. This was my first answer in stack flow. :)

Resources