35

I have two rays on a 2D plane that extend to infinity, but both have a starting point. They are both described by a starting point and a vector in the direction of the ray extending to infinity. I want to find out if the two rays intersect, but I don't need to know where they intersect (it's part of a collision detection algorithm).

Everything I have looked at so far describes finding the intersection point of two lines or line segments. Is there a fast algorithm to solve this?

11
  • 2D or 3D? If the former simply check and see if the slope is the same for both: if so they are either parallel or the same line. Otherwise they will intersect. Commented May 28, 2010 at 18:35
  • 2
    These are rays, not lines, then? All lines intersect in two dimensions, unless they're parallel. Commented May 28, 2010 at 18:35
  • @fbereto: sorry, 2D plane. Edited to reflect that. Commented May 28, 2010 at 18:36
  • @Carl Norum: Yea, your right. Sorry you're right Commented May 28, 2010 at 18:37
  • 1
    It is tempting, at a first glance, to look for some fancy use of vector products and comparing angles, but think about calculations needed to get those products and look at Adam's or Peter's solution. Calculating the determinants for the equation set is almost the same as calculating vector products Commented May 28, 2010 at 19:27

9 Answers 9

43

Let's assume that the first ray is a, the second ray is b, .s is the ray's starting point (a 2D vector), and .d is the ray's direction (also a 2D vector), and × denotes a 2D cross product, defined as:

a × b = a.x * b.y - a.y * b.x 

After factoring out the common terms, the solution to the intersection equations comes to:

d = b.s - a.s det = b.d × a.d u = d × b.d / det v = d × a.d / det 

If (and only if) det == 0, the rays are parallel and there are zero (or there is an infinite number of) intersection points. The execution of this code would lead to a division by zero.

Otherwise, if both u and v are positive numbers, the rays have a unique intersection point and u is the distance between a.s and the intersection point, while v is the distance between b.s and the intersection point.

After de-vectorizing and inlining the cross product, this becomes:

dx = b.s.x - a.s.x dy = b.s.y - a.s.y det = b.d.x * a.d.y - b.d.y * a.d.x u = (dy * b.d.x - dx * b.d.y) / det v = (dy * a.d.x - dx * a.d.y) / det 

Five subtractions, six multiplications and two divisions.

If you don't care about the intersection point or the distance to it, these two divisons can be replaced by num * denom < 0 or sign(num) != sign(denom), depending on what is more efficient on your target machine.

On the other hand, if you'd actually want to find the intersection point, you have to input one of these solutions to the respective ray equation.

p = a.s + a.d * u 

...which should be aproximately equal (as far as the numerical precision allows) to...

p = b.s + b.d * v 
Sign up to request clarification or add additional context in comments.

4 Comments

For those who were confused by the derivation, here it is: math.stackexchange.com/questions/2788943
The link has expired.
Small nit: for the case of det==0, it could mean there is no intersection, or it could also mean there is intersection everywhere (the input lines overlap). Perhaps it could more accurately be phrased "the rays do not have a unique intersection".
As I had no idea what the author disagreed about, I removed that bit. I also included a vectorized solution. After this whole cleanup, I still don't understand the difference between this and the other highly-upvoted answer.
33

Let's assume we're given two rays a and b with starting points (origin vectors) a.s, b.s, and direction vectors a.d, b.d.

The two lines intersect if there is an intersection point p like:

p = a.s + a.d * u p = b.s + b.d * v 

If this equation system has a solution for u >= 0 and v >= 0 (the positive direction is what makes them rays), the rays intersect.

For the x/y coordinates of the 2d vectors, this means:

p.x = a.s.x + a.d.x * u p.y = a.s.y + a.d.y * u p.x = a.s.x + b.d.x * v p.y = b.s.y + b.d.y * v 

Further steps:

as.x + ad.x * u = bs.x + bd.x * v as.y + ad.y * u = bs.y + bd.y * v 

Solving against v:

v := (as.x + ad.x * u - bs.x) / bd.x 

Inserting and solving against u:

a.s.y + a.d.y * u = b.s.y + b.d.y * ((a.s.x + a.d.x * u - b.s.x) / bd.x) u := (a.s.y * b.d.x + b.d.y * b.s.x - b.s.y * b.d.x - b.d.y * a.s.x ) / (a.d.x * b.d.y - a.d.y * b.d.x) 

After replacing the respective terms with a cross product, this becomes:

u := (b.s × b.d + b.d × a.s.y) / (a.d × b.d) 

Calculate u, then calculate v, if both are positive the rays intersect, else not.

5 Comments

how do you solve u from the last formula? it includes itself.
whoops, I inserted 'v' into the wrong equation. It's fixed now.
I understand this post is old, and I am not sure why or how, but this solution causes different solutions when the vector a and be are switched, notably when the solution would have been v = 2 but it equals 1 instead. The points I used were: for the first vector (7.64475393f, 5.59931898f), (6.30824f, 4.91833f) for the second vector (6.43122959f, 7.98099709f),(6.43122864f, 6.48099709f)
How do you go from as.y + ad.y * u = bs.y + bd.y * ((as.x + ad.x * u - bs.x) / bd.x) to u := (as.y*bd.x + bd.y*bs.x - bs.y*bd.x - bd.y*as.x ) / (ad.x*bd.y - ad.y*bd.x) ?
Do I understand correctly that this solution is just incorrect? The currently top-voted answer takes the same assumptions but reaches different results.
4

c++ for Guntners solution

bool RaysIntersection(const Point& as, const Point& ad, const Point& bs, const Point& bd, Point& result) { if (as == bs) { result = as; return true; } auto dx = bs.X - as.X; auto dy = bs.Y - as.Y; auto det = bd.X * ad.Y - bd.Y * ad.X; if (det != 0) { // near parallel line will yield noisy results double u = (dy * bd.X - dx * bd.Y) / (double)det; double v = (dy * ad.X - dx * ad.Y) / (double)det; if (u >= 0 && v >= 0) { result = as + ad * u; return true; } } return false; } 

Comments

3

A ray can be represented by the set of points A + Vt, where A is the starting point, V is a vector indicating the direction of the ray, and t >= 0 is the parameter. Thus, to determine if two rays intersect, do this:

bool DoRaysIntersect(Ray r1, Ray r2) { // Solve the following equations for t1 and t2: // r1.A.x + r1.V.x * t1 == r2.A.x + r2.V.x * t2 // r1.A.y + r1.V.y * t1 == r2.A.y + r2.V.y * t2 if(no solution) // (e.g. parallel lines) { if(r1 == r2) // same ray? return true; else return false; // parallel, non-intersecting } else // unique solution { if(t1 >= 0 && t2 >= 0) return true; else return false; // they would intersect if they are lines, but they are not lines } } 

Comments

3

I found this post while trying to find the intersection point between two rays, based on other answers here. Just in case someone else has arrived here looking for the same answer, here's an answer in TypeScript / JavaScript.

/** * Get the intersection of two rays, with origin points p0 and p1, and direction vectors n0 and n1. * @param p0 The origin point of the first ray * @param n0 The direction vector of the first ray * @param p1 The origin point of the second ray * @param n1 The direction vector of the second ray * @returns */ export function getRaysIntersection( p0: number[], n0: number[], p1: number[], n1: number[] ): number[] | undefined { const dx = p1[0] - p0[0]; const dy = p1[1] - p0[1]; const det = n1[0] * n0[1] - n1[1] * n0[0]; const u = (dy * n1[0] - dx * n1[1]) / det; const v = (dy * n0[0] - dx * n0[1]) / det; if (u < 0 || v < 0) return undefined; // Might intersect as lines, but as rays. const m0 = n0[1] / n0[0]; const m1 = n1[1] / n1[0]; const b0 = p0[1] - m0 * p0[0]; const b1 = p1[1] - m1 * p1[0]; const x = (b1 - b0) / (m0 - m1); const y = m0 * x + b0; return Number.isFinite(x) ? [x, y] : undefined; } 

Demo here: https://codesandbox.io/s/intersection-of-two-rays-mcwst

1 Comment

This fails with the ray directions are axis aligned...
2

Lines are represented by a point p and a vector v:

line = p + a * v (for all a)

Rays are (the positive) half of that line:

ray = p + a * v (for all a >= 0)

To determine if two lines intersect, set them equal and solve:

intersection occurs where p1 + a1 * v1 = p2 + a2 * v2
(note that there are two unknowns, a1 and a2, and two equations, since the p's and v's are multi-dimensional)

Solve for a1 and a2 - if they are both non-negative, they intersect. If one is negative, they don't intersect.

Comments

2

GeomAlgorithms.com has some pretty sweet algorithms dealing with lines in 3D... Generally speaking though, the probability of two lines intersecting in 3D space is really quite low.

In 2D, you have to check the slope. If the slope is not equal then they intersect. If the slope is equal, they intersect if a point on them has the same x-coordinate or the same y-coordinate.

3 Comments

The question specifically states that it's limited to 2d.
@glowcoder It didn't state that at the time that I answered originally, edited post to describe 2-D algorithm.
@glowcoder: its ok, if it was in 3D all i need to do is set all z components to zero and simplify the equations and it should work. Thanks vicatcu, ill check out the site.
0

I want only to check if the two rays intersect. I will go about it by calculating the direction of rotation of two "triangles" created from the two rays. They aren't really triangles, but from a mathematical standpoint, if I only wanted to calculate the rotation of the triangle, I only need two vectors with a common starting point, and the rest doesn't matter.

The first triangle will be formed by two vectors and a starting point. The starting point will be the first ray's starting point. The first vector will be the first ray's direction vector. The second vector will be the vector form the first ray's starting point to the second ray's starting point. From here we take the cross product of the two vectors and note the sign.

We do this again for the second triangle. Again, the starting point is the second ray's starting point. The first vector is the second ray's direction and the second vector is from the second ray's starting point to the first ray's starting point. We take the cross product again of the vectors and note the sign.

Now we simply take the two signs and check if they are the same. If they are the same, we have no intersection. If they are different we have an intersection. That's it!

Here's some psudo code:

sign1 = cross(vector1, point1 - point2) sign2 = cross(vector2, point2 - point1) if (sign1 * sign2 < 0) // If signs are mismatched, they will multiply to be negative return intersection 

It works out to be five multiplications, six subtractions, and one comparison.

4 Comments

Ahh you got it. Didn't see that.
Don't know if the "edge cases" are necessary to consider but I edited my answer to describe them.
An edge case in my application is very unlikely and even a false positive doesn't really hurt me. I need raw speed since I'm iterating over possibly billions of such cases. I'll just simply say if anything collinear we will just call it an intersection rather than add a few extra statements to nail down exactly what happened.
No, this is wrong. See my comment on John at CashCommons' equally incorrect solution.
-3

If the lines are of infinite length, then they will always intersect, unless they are parallel. To check if they are parallel, find the slope of each line and compare them. The slope will just be (y2-y1)/(x2-x1).

4 Comments

Lines are not rays. And parallel lines can intersect as well (if they are the same line).
Also if the 2D space is curved, parallel lines can intersect (latitudes and longitudes for example).
Sorry i edited my post to reflect what i was really asking. They lines are actually rays with a starting point but no end. Checking the slope will not give me the answer as it is possible for the "lines" to intersect on the "wrong" side of the point which counts as a miss.
I believe the question implies that they are not infinite in both directions: they have a starting vector and a direction vector. Thus a line starting at (1,2) and going off on (0,1) will not intersect with a line starting at (2,1) and going off on (1,0). If they were lines rather than 'rays', then of course your answer would be correct.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.