如何找到距离一条直线固定垂直距离的点?

55
我有一条在线窗口中绘制,并允许用户拖动,我的线由两个点定义:(x1,y1)和(x2,y2)。但现在我想在我的线末端绘制“帽子”,即在每个端点处都是短的垂直线。这些帽子应该是N像素长。
因此,要在端点(x1,y1)处绘制我的“帽子”线,我需要找到两个点,形成垂直线,并且每个点距离点(x1,y1)为N/2像素。
那么,如何计算一个点(x3,y3),给定它需要与已知线的末点(x1,y1)保持垂直距离N/2,即由(x1,y1)和(x2,y2)定义的线?

有关详细的解决方案,请参见此处:https://dev59.com/TmQm5IYBdhLWcg3w-i9L#17195324。 - legends2k
4个回答

95

你需要计算一个垂直于线段的单位向量。避免计算斜率,因为这可能会导致除以零错误。

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

1
我一直在想,可能可以通过使用Breshenham's Line来避免那个讨厌的sqrt,但我一时想不出来。 - Paul Tomblin
2
我认为你的计算或点3和4中存在符号错误。在最后四行中使用(+ - - +)或(- + + -),对吗? - dmckee --- ex-moderator kitten
计算 x3 应该使用 dx 而不是 dy,对吗? - jameswelle
5
请在JSFiddle上制作该公式的可视化:http://jsfiddle.net/n2gqw8of 你可以更改ax、ay和bx、by的值以修改线条,观察垂直线相应地调整... - Kevin Jurkowski
1
@PaulTomblin 一个近似的解决方案是将该行本身旋转90度,使用 (dx,dy)->(-dy,dx);然后通过 N/L_aprx 进行近似缩放,其中 L_aprx = (|dx|+|dy|)*0.83。这可能已经足够好了。两个刻度线的长度将会偏离 (10% (+-10%)) - Will Ness
1
有人能解释一下这个伪代码是做什么的吗?我知道它可以工作,但我的问题是怎么做到的? - Santhosh

7
您只需评估正交单位向量并乘以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

4

由于2到1和1到3的向量垂直,它们的点积为0。

这让你有两个未知数:从1到3的x(x13)和从1到3的y(y13)

使用勾股定理得到这些未知数的另一个方程。

通过代换解决每个未知数...

这需要平方和开方,因此您会失去与方程相关联的符号。

要确定符号,请考虑:

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

已知:点1坐标为x1,y1

已知:点2坐标为x2,y2

x21 = x1 - x2
y21 = y1 - y2

已知:距离 |1->3| : N/2

方程 a: 勾股定理

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

已知:角2-1-3为直角

向量2->1和1->3互相垂直

2->1点乘1->3等于0

方程b:点积等于0

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

x13和y13之间的比率:

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

x13 = -phi*y13

方程a:已知比例求解y13

  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

方程a:以比例解决x13问题

  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

压缩
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

我通常不会这样做,但我在工作中解决了这个问题,并且认为彻底讲解它将有助于巩固我的知识。


1

如果你想避免使用sqrt函数,可以按照以下方法操作:

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接