How do you find a point at a given perpendicular distance from a line?

AlgorithmMathGraphicsGeometryCoordinates

Algorithm Problem Overview


I have a line that I draw in a window and I let the user drag it around. So, my line is defined by two points: (x1,y1) and (x2,y2). But now I would like to draw "caps" at the end of my line, that is, short perpendicular lines at each of my end points. The caps should be N pixels in length.

Thus, to draw my "cap" line at end point (x1,y1), I need to find two points that form a perpendicular line and where each of its points are N/2 pixels away from the point (x1,y1).

So how do you calculate a point (x3,y3) given it needs to be at a perpendicular distance N/2 away from the end point (x1,y1) of a known line, i.e. the line defined by (x1,y1) and (x2,y2)?

Algorithm Solutions


Solution 1 - Algorithm

You need to compute a unit vector that's perpendicular to the line segment. Avoid computing the slope because that can lead to divide by zero errors.

dx = x1-x2
dy = y1-y2
dist = sqrt(dx*dx + dy*dy)
dx /= dist
dy /= dist
x3 = x1 + (N/2)*dy
y3 = y1 - (N/2)*dx
x4 = x1 - (N/2)*dy
y4 = y1 + (N/2)*dx

Solution 2 - Algorithm

You just evaluate the orthogonal versor and multiply by N/2

vx = x2-x1
vy = y2-y1
len = sqrt( vx*vx + vy*vy )
ux = -vy/len
uy = vx/len

x3 = x1 + N/2 * ux
Y3 = y1 + N/2 * uy

x4 = x1 - N/2 * ux
Y4 = y1 - N/2 * uy

Solution 3 - Algorithm

Since the vectors from 2 to 1 and 1 to 3 are perpendicular, their dot product is 0.

This leaves you with two unknowns: x from 1 to 3 (x13), and y from 1 to 3 (y13)

Use the Pythagorean theorem to get another equation for those unknowns.

Solve for each unknown by substitution...

This requires squaring and unsquaring, so you lose the sign associated with your equations.

To determine the sign, consider:

while x21 is negative, y13 will be positive
while x21 is positive, y13 will be negative
while y21 is positive, x13 will be positive
while y21 is negative, x13 will be negative

Known: point 1 : x1 , y1

Known: point 2 : x2 , y2

x21 = x1 - x2
y21 = y1 - y2

Known: distance |1->3| : N/2

equation a: Pythagorean theorem

x13^2 + y13^2 = |1->3|^2
x13^2 + y13^2 = (N/2)^2

Known: angle 2-1-3 : right angle

vectors 2->1 and 1->3 are perpendicular

2->1 dot 1->3 is 0

equation b: dot product = 0

x21*x13 + y21*y13 = 2->1 dot 1->3
x21*x13 + y21*y13 = 0

ratio b/w x13 and y13:

x21*x13 = -y21*y13
x13 = -(y21/x21)y13

x13 = -phi*y13

equation a: solved for y13 with ratio

  plug x13 into a
phi^2*y13^2 + y13^2 = |1->3|^2

  factor out y13
y13^2 * (phi^2 + 1) = 

  plug in phi
y13^2 * (y21^2/x21^2 + 1) = 

  multiply both sides by x21^2
y13^2 * (y21^2 + x21^2) = |1->3|^2 * x21^2

  plug in Pythagorean theorem of 2->1
y13^2 * |2->1|^2 = |1->3|^2 * x21^2

  take square root of both sides
y13 * |2->1| = |1->3| * x21

  divide both sides by the length of 1->2
y13 = (|1->3|/|2->1|) *x21

  lets call the ratio of 1->3 to 2->1 lengths psi
y13 = psi * x21

  check the signs
    when x21 is negative, y13 will be positive
    when x21 is positive, y13 will be negative

y13 = -psi * x21

equation a: solved for x13 with ratio

  plug y13 into a
x13^2 + x13^2/phi^2 = |1->3|^2

  factor out x13
x13^2 * (1 + 1/phi^2) = 

  plug in phi
x13^2 * (1 + x21^2/y21^2) = 

  multiply both sides by y21^2
x13^2 * (y21^2 + x21^2) = |1->3|^2 * y21^2

  plug in Pythagorean theorem of 2->1
x13^2 * |2->1|^2 = |1->3|^2 * y21^2

  take square root of both sides
x13 * |2->1| = |1->3| * y21

  divide both sides by the length of 2->1
x13 = (|1->3|/|2->1|) *y21

  lets call the ratio of |1->3| to |2->1| psi
x13 = psi * y21

  check the signs
    when y21 is negative, x13 will be negative
    when y21 is positive, x13 will be negative

x13 = psi * y21

to condense

x21 = x1 - x2
y21 = y1 - y2

|2->1| = sqrt( x21^2 + y^21^2 )
|1->3| = N/2

psi = |1->3|/|2->1|

y13 = -psi * x21
x13 =  psi * y21

I normally wouldn't do this, but I solved it at work and thought that explaining it thoroughly would help me solidify my knowledge.

Solution 4 - Algorithm

If you want to avoid a sqrt, do the following:

in: line_length, cap_length, rotation, position of line centre

define points:
  tl (-line_length/2, cap_length)
  tr (line_length/2, cap_length)
  bl (-line_length/2, -cap_length)
  br (line_length/2, -cap_length)

rotate the four points by 'rotation'
offset four points by 'position'

drawline (midpoint tl,bl to midpoint tr,br)
drawline (tl to bl)
drawline (tr to br)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAZDeanView Question on Stackoverflow
Solution 1 - AlgorithmDavid NehmeView Answer on Stackoverflow
Solution 2 - AlgorithmGiacomo Degli EspostiView Answer on Stackoverflow
Solution 3 - Algorithmuser677616View Answer on Stackoverflow
Solution 4 - AlgorithmSkizzView Answer on Stackoverflow