3D Line collision

Not long ago I found myself with the necessity of a Line class where I could compute the relative position of two lines and get the intersection point (if any). I’ve used C# to code this as I was using it at work when I needed this class, but should be easily portable to other languages like Java or C++.

A line can be represented in many different ways, but I chose to represent it with the vector equation:

l = p + k \cdot \vec v

wherelis the line,pa point of the line,kan scalar and\vec vis the direction vector.

To compute the relative position of two lines (A and B from now on) we could take 2 (or more) different approaches:

    1. Compute their relative distance, if its zero (or close to) we can assume they intersect.
    2. Determine if their direction vectors are parallel (so the lines are parallel or overlapping) and if they aren’t solve the resulting equation system when you equal their line equations. If there’s a solution that is the intersection point, if there is no solution, they don’t intersect.

The first option can be found here: http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm or here: http://www.vitutor.com/geometry/distance/distance_lines.html

For the second option we will follow this flow chart:

Line-line relative position algorithm (Option 2)

As you can see this algorithm takes two lines (A & B) as input and makes some checks/actions with them so we can know their relative position (don’t worry if you don’t understand that math notation; keep reading).

The first check is where we will know if the lines can be overlapping/parallel or intersecting/skew; this is the point where floating point math error will cause us trouble because every way that I found to check if two vectors are linearly dependent (\vec v = k \cdot \vec {v'}) depends on the equality operator (==) between floating point numbers (something you can’t trust). More info here: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

We could use the fact that vectors\vec vand\vec {v'}are linearly dependent if and only if their cross product equals the zero vector (0, 0, 0).

Assuming that they are dependent, we need to obtain a pointafrom the line A to check if it’s in line B.

As we are using the vector equation we have a point that it’s in the line, so we need to check if this point is in the other line; problem is that every way that I found to check if a point is contained in a line needs those equality checks (== operator) between floating point numbers.

If vectors are linearly independent we can go for the interesting part, the intersection!

This are the line equations:

\begin{array}{rcr}    l_0 & = & (x_0, y_0, z_0)+ k_0 \cdot (a_0, b_0, c_0)\\    l_1 & = & (x_1, y_1, z_1)+ k_1 \cdot (a_1, b_1, c_1)    \end{array}

To get the intersection point we need to solve the equation system that results froml_0 = l_1:

\begin{array}{rcl}    x_0 + k_0 a_0 & = & x_1 + k_1 a_1 \\    y_0 + k_0 b_0 & = & y_1 + k_1 b_1 \\    z_0 + k_0 c_0 & = & z_1 + k_1 c_1    \end{array}

We isolatek_0andk_1from the x, y coordinates formulas:

k_0 = (x_1 - x_0 + a_1 k_1)/a_0

k_1 = (y_0 - y_1 + b_0 k_0)/b_1

I’ll skip all that error-prone & hard to follow math equation solving for you:

k_1 = (a_0 (y_0 - y_1) + b_0 (x_1 - x_0)) / (b_1 a_0 - b_0 a_1)

Withk_1we can use the parametric equations of the line to get the intersection point, for that purpose I have this function inside the line class:

/// <summary>
/// Returns a point from this line using the parametric equation.
/// </summary>
/// <param name="k">Parameter used to get the point from this line.</param>
public Vector GetPoint(float k)
{
    return new Vector(this.point.X + this.direction.X * k,
                      this.point.Y + this.direction.Y * k,
                      this.point.Z + this.direction.Z * k);
}

But if you take a look at the latestk_1equation you’ll see that there’s a big chance that we end up dividing by something by zero or even 0 by 0 !!

This happens only when there is no intersection between the lines; in C# (I think that Java works the same way, can’t say for sure) float and double types have -Infinity, +Infinity and NaN values to avoid throwing an exception when that occurs, in other languages we must control this manually and avoid those divisions.

In this case ifk_1ends up with a “strange” value we know the lines do not intersect (skew).

Note that if you do not follow the option 2 algorithm strange values ink_1could also mean that the lines overlap.

So this is the intersection method:

/// <summary>
/// Gets the intersection point of this and the given lines (if any).
/// </summary>
/// <returns>Whether this and the given line intersect.</returns>
public bool GetIntersection(Line3 other, ref Point intersectionPoint)
{
    // Don't worry about this, it's the k1 that we calculated before
    float k1 = (this.direction.X * (this.point.Y - other.point.Y)
                + this.direction.Y * (other.point.X - this.point.X))
               / (other.direction.Y * this.direction.X - this.direction.Y * other.direction.X);

    if (float.IsNaN(k1) || float.IsInfinity(k1))
    {
        // strange values indicate that lines are skew or overlapping
        return false;
    }
    else
    {
        intersectionPoint = other.GetPoint(k1);
        return true;
    }
}

While getting the relative position of a pair of lines gets pretty ugly (because of floating point number errors), getting the intersection point between two lines is not that hard; feel free to do whatever you want with it!

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s