在另一条直线的某个点处画一个固定长度的垂线

12

我有两个点A(10,20)和B(15,30)。这些点构成一条线段AB。我需要在点B上画出一条垂线CD,长度为6(每个方向3个单位),使用Python。

我已经使用以下代码获得了线段AB的一些属性:

from scipy import stats
x = [10,15]
y = [20,30]
slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
我该如何计算C和D的位置。我需要它们的X和Y值。 enter image description here C和D的值将被用于使用Shapely库完成另一个目标。

你在问一个数学问题:如何计算点 CD - wwii
Python代码很好,但我也可以使用数学方程式。 - Sourav
4个回答

19

既然您对使用Shapely感兴趣, 我能想到的最简单的获取垂直线的方法是使用parallel_offset 方法获取两条与AB平行的线并连接它们的端点:

from shapely.geometry import LineString

a = (10, 20)
b = (15, 30)
cd_length = 6

ab = LineString([a, b])
left = ab.parallel_offset(cd_length / 2, 'left')
right = ab.parallel_offset(cd_length / 2, 'right')
c = left.boundary[1]
d = right.boundary[0]  # note the different orientation for right offset
cd = LineString([c, d])

这里输入图片描述

CD的坐标是:

>>> c.x, c.y
(12.316718427000252, 31.341640786499873)
>>> d.x, d.y
(17.683281572999746, 28.658359213500127)

我不知道它有多快,但我喜欢这个解决方案的简洁性。 - Laurent R
厉害啊! - Yu Da Chi

7
如果slope是AB的斜率,那么CD的斜率为-1/slope。这等于垂直变化与水平变化之比:dy/dx=-1/slope。这给出了dx=-slope*dx。通过勾股定理,你有3**2=dy**2+dx**2。代入dx,你就得到:

3**2=(-slope*dy)**2+dy**2
3**2=(slope**2 + 1)*dy**2
dy**2=3**2/(slope**2+1)
dy=math.sqrt(3**2/(slope**2+1))

然后你可以得到dx=-slope*dy。最后,你可以使用dxdy来得到C和D。所以代码将会是:

import math
dy = math.sqrt(3**2/(slope**2+1))
dx = -slope*dy
C[0] = B[0] + dx
C[1] = B[1] + dy
D[0] = B[0] - dx
D[1] = B[1] - dy

(请注意,虽然 math.sqrt 只返回一个数,但通常存在正负平方根。C 对应于正平方根,D 对应于负平方根。)

2
你应该使用向量来计算点的位置。
  • 创建向量AB
  • 计算其归一化垂线
  • 加上或减去3倍于此的B
借助一个简单、可重复使用的Vector类,计算非常简单,阅读起来就像英语:
找到与点B距离为3AB垂直的点:
P1 = B + (B-A).perp().normalized() * 3 P2 = B + (B-A).perp().normalized() * 3
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    def dot(self, other):
        return self.x * other.x + self.y * other.y
    def norm(self):
        return self.dot(self)**0.5
    def normalized(self):
        norm = self.norm()
        return Vector(self.x / norm, self.y / norm)
    def perp(self):
        return Vector(1, -self.x / self.y)
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    def __str__(self):
        return f'({self.x}, {self.y})'


A = Vector(10, 20)
B = Vector(15, 30)

AB = B - A  
AB_perp_normed = AB.perp().normalized()
P1 = B + AB_perp_normed * 3
P2 = B - AB_perp_normed * 3

print(f'Point{P1}, and Point{P2}')

output:

Point(17.683281572999746, 28.658359213500127), and Point(12.316718427000252, 31.341640786499873)

1
当A = Vector(10, 20)和B = Vector(15, 20)时,你的AB.perf()在javascript中会返回{...,y:Nan}。当y不变时该如何处理? - Thakur Karthik

0
如果我们有一条与x轴或y轴平行的直线,那么我们可以向Vector类中添加以下两种方法。
def perptoy(self):
    return Vector(1, 0)
def perptox(self):
    return Vector(1, -10000) // any big number will do instead of -inf

AB = B - A  
if (A.y == B.y):
   AB_perp_normed = AB.perptox().normalized();
elif (A.x == B.x):
   AB_perp_normed = AB.perptoy().normalized();
else:
   AB_perp_normed = AB.perp().normalized();

其余的步骤与之前的帖子相同。


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