【发布时间】:2011-04-19 19:03:55
【问题描述】:
如何检查一个点是否低于一条线?
我有以下数据:
Line [ {x1,y1}, {x2,y2} ]
Points {xA,yA}, {xB,yB} ...
我需要在python中编写一个小算法来检测线的一侧和另一侧的点。
谢谢
【问题讨论】:
如何检查一个点是否低于一条线?
我有以下数据:
Line [ {x1,y1}, {x2,y2} ]
Points {xA,yA}, {xB,yB} ...
我需要在python中编写一个小算法来检测线的一侧和另一侧的点。
谢谢
【问题讨论】:
感谢Edmund 的解决方案,我为该行编写了一个模块来计算这个和其他一些用c++ 实现的简单行操作,运行速度非常快。你可以通过pip安装FastLine,然后这样使用:
from FastLine import Line
# define a line by two points
l1 = Line(p1=(0,0), p2=(10,10))
# define a line by its slope and intercept
l2 = Line(m=4, b=-1)
>>> l1.crossed_by((20,50)) # specific side
1
>>> l1.crossed_by((50,50)) # on the line
0
>>> l1.crossed_by((-20,-50)) # opposite side
-1
【讨论】:
您可以尝试使用叉积 -- http://en.wikipedia.org/wiki/Cross_product。
v1 = (x2-x1, y2-y1) # Vector 1
v2 = (x2-xA, y2-yA) # Vector 2
xp = v1[0]*v2[1] - v1[1]*v2[0] # Cross product
if xp > 0:
print('on one side')
elif xp < 0:
print('on the other')
else:
print('on the same line!')
您需要校准每一面的内容。如果您希望它位于“下方”或“上方”,则需要确保线上的点是水平排序的。
我还没有测试过。
编辑我最初输入了点积公式。 :o
编辑 2 哦,我将坐标放入集合而不是元组。如果您运行的是相当现代的 Python 版本,则将 namedtuple('point', 'x y') 用于向量会很好。
【讨论】:
math.cos(math.pi/2) 给出了 6.1230317691118863e-017,所以我猜 1e-15 或 1e-16 范围内的 epsilon 大约是正确的. (将其放入您自己的常量 EPS 中,这样您就可以轻松地调整它,只需在一个地方进行调整,而不是在您进行浮点比较的任何地方进行调整。)
你可以尝试使用叉积,但诀窍是如何选择点来形成一个向量,这里我从点中选择最近的点,假设我得到了 pointA(你可以公平地循环点来计算与循环的距离指向线):
v1 = {x2-x1, y2-y1} # Vector 1
v2 = {xA-x1, yA-y1} # Vector 2
cross_product = v1.x*v2.y - v1.y*v2.x
if cross_product > 0:
print 'pointA is on the counter-clockwise side of line'
elif cross_product < 0:
print 'pointA is on the clockwise side of line'
else:
print 'pointA is exactly on the line'
【讨论】:
假设您给出了 2 个点 A、B,并且您想知道第三个点 C 位于哪个 halfplane。作为标准的术语“下方”和“上方”非常模糊,因此您需要一个参考点,例如原点。只需确保此参考点与 A 和 B 不共线即可。
您现在拥有的是一个三角形(A、B、C)。使用行列式,您可以计算有符号面积(see here 或 here)。这里唯一有趣的是记住这个标志。
下一步:对于给定的点 D,计算三角形的有符号面积(A,B,D)。如果结果与参考三角形的区域具有相同的符号-> C 和 D 在 (A, B) 的同一侧。如果符号不同 -> C 和 D 位于线的相对两侧。如果 (A, B, D) 的面积为 0,则 A、B 和 D 共线。注意:使用 Python 内置 cmp 来比较三角形区域。
【讨论】: