Skip to content

Instantly share code, notes, and snippets.

@wavebeem
Created March 31, 2021 22:08
Show Gist options
  • Save wavebeem/16cd0aecd5ed70c7e38bebbd9979e0b3 to your computer and use it in GitHub Desktop.
Save wavebeem/16cd0aecd5ed70c7e38bebbd9979e0b3 to your computer and use it in GitHub Desktop.

Snap Point To Line Segment

Segment bisection cursor snapping

                                              +-------------+
                                              |             |
                                              |             |
                                              |             |
                                              |             |
                                              |             |
                                              +-------------+
                                               XXXX
                                             XXX        p2
                                           XX
                                         XX
                         +------------+XX
                         |            |
                         |            |
                         |            |
                         |            |
                         |            |
                         +------------+X
                      XXXX              XXX
                   XXXX       p4           XXX
                 XXX                         XX
   +-----------+XX                             XXXX
   |           |                                  XXXX  +------------+
   |           |                                     XX |            |
   |           |                                       X|            |
   |           |                                        |            |
   |           |                                        |            |
   +-----------+                                        |            |
                                                        |            |
                                                        +------------+
p1
                                                        p3

Point definitions

p1 is the first node on the hovered segment.

p2 is the second node on the hovered segment.

p3 is the mouse cursor position.

p4 is the point we are trying to solve for.

Other notes

p3 to p4 will form a perpendicular line to the p1 to p2 segment, because that is the shortest distance to the segment. A non perpendicular line would be longer, so we don't want that.

Finding the point

We can think of this problem as finding the intersection of two line equations once we find the equations for the lines.

For the p1 to p2 segment we know both X, Y pairs so we can easily find the equation using point slope form:

y = m(x - p1.x) + p1.y

Where m is the slope of the line defined by the "rise over run", which can be calculated as this fraction:

    p1.y - p2.y
m = -----------
    p1.x - p2.x

We also know that the slope of a perpendicular line is the negative reciprocal of the slope, meaning if the slope is m, the perpendicular line's slope is -1 / m.

See https://www.mathsisfun.com/algebra/line-parallel-perpendicular.html.

So the p1 to p2 segment's equation is:

    p1.y - p2.y
y = ----------- * (x - p1.x) + p1.y
    p1.x - p2.x

To simplify writing the equation, we'll call the slope m1 here:

y = m1 * (x - p1.x) + p1.y

We only know one point on the perpendicular segment, but we can figure out the slope via -1/m formula, so that gives us:

         p1.x - p2.x
y = -1 * ----------- * (x - p3.x) + p3.y
         p1.y - p2.y

To simplify writing the equation, we'll call the slope m2 here:

y = m2 * (x - p3.x) + p3.y

In order to find where they intersect, we can set the two equations equal to each other and solve for X using algebra.

m1 * (x - p1.x) + p1.y = m2 * (x - p3.x) + p3.y

Subtract p1.y from both sides:

m1 * (x - p1.x) = m2 * (x - p3.x) + p3.y - p1.y

Distribute the multiplication of m1 over the the subtraction:

(m1 * x) - (m1 * p1.x) = m2 * (x - p3.x) + p3.y - p1.y

Distribute the multiplication of m2 over the the subtraction:

(m1 * x) - (m1 * p1.x) = (m2 * x) - (m2 * p3.x) + p3.y - p1.y

We want to get all the X on the left side, so we will subtact (m2 * x) from both sides:

(m1 * x) - (m1 * p1.x) - (m2 * x) = - (m2 * p3.x) + p3.y - p1.y

We want to isolate the X's so we'll add the (m1 * p1.x) to both sides:

(m1 * x) - (m2 * x) = - (m2 * p3.x) + p3.y - p1.y + (m1 * p1.x)

Now we can un-distribute the multiplication over the subtraction on the left:

(m1 - m2) * x = - (m2 * p3.x) + p3.y - p1.y + (m1 * p1.x)

The final step is dividing by m1 - m2:

    -(m2 * p3.x) + p3.y - p1.y + (m1 * p1.x)
x = ----------------------------------------
                  (m1 - m2)

So at this point, we know the equation solved for Y for the p3 to p4 segment, and we know an X value, so we plug in that X value to get the Y value, leaving us with the X, Y coordinate pair for p4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment