当前位置:  开发笔记 > 编程语言 > 正文

如何确定线段上两个点之间的点?

如何解决《如何确定线段上两个点之间的点?》经验,为你挑选了5个好方法。

假设你有一个带有2个点(称为a和b)的二维平面,它由x整数和每个点的y整数表示.

如何确定a和b定义的线段上是否有另一个点c?

我最常使用python,但任何语言的示例都会有所帮助.



1> Cyrille Ka..:

检查(ba)和(ca)的叉积是否为0,如Darius Bacon告诉你的那样,a,b和c点是否对齐.

但是,如果你想知道c是否在a和b之间,你还必须检查(ba)和(ca)的点积正的并且小于 a和b之间的距离的平方.

在非优化伪代码中:

def isBetween(a, b, c):
    crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y)

    # compare versus epsilon for floating point values, or != 0 if using integers
    if abs(crossproduct) > epsilon:
        return False

    dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if dotproduct < 0:
        return False

    squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
    if dotproduct > squaredlengthba:
        return False

    return True


交叉积的绝对值是由三个点形成的三角形的面积的两倍(符号表示侧面是第三点)所以恕我直言,你应该使用与两个端点之间的距离成比例的epsilon.
`-epsilon 您应该重命名a,b,c以使其更清晰,哪些是段端点,哪个是查询点.
你能告诉我们为什么不能用整数工作吗?如果epsilon检查被"!= 0"替换,我没有看到问题.
是的,额外的括号只是一个错字.在有人说了什么之前已经过去了4年.:)

2> Jules..:

这是我如何做到的:

def distance(a,b):
    return sqrt((a.x - b.x)**2 + (a.y - b.y)**2)

def is_between(a,c,b):
    return distance(a,c) + distance(c,b) == distance(a,b)


`-epsilon <(距离(a,c)+距离(c,b) - 距离(a,b))这是一个优雅的解决方案.
唯一的问题是数值稳定性 - 数字的差异等等很容易失去精度.
@NeonWarge:sqrt()返回一个浮点数。对于大多数浮点数,[`==`是错误的事情](https://www.python.org/dev/peps/pep-0485/#rationale)。可以使用[`math.isclose()`](https://docs.python.org/3/library/math.html#math.isclose)。在2008年没有`math.isclose()`,因此我为`epsilon`提供了显式的不等式(math.isclose()中的`abs_tol`)。

3> Darius Bacon..:

检查b-a和的叉积c-a是否为0:表示所有点都是共线的.如果是,检查c坐标是否在a's和b's之间.请使用x或y坐标,只要ab一些对轴单独(或他们是在两个相同的).

def is_on(a, b, c):
    "Return true iff point c intersects the line segment from a to b."
    # (or the degenerate case that all 3 points are coincident)
    return (collinear(a, b, c)
            and (within(a.x, c.x, b.x) if a.x != b.x else 
                 within(a.y, c.y, b.y)))

def collinear(a, b, c):
    "Return true iff a, b, and c all lie on the same line."
    return (b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y)

def within(p, q, r):
    "Return true iff q is between p and r (inclusive)."
    return p <= q <= r or r <= q <= p

这个答案过去是三个更新的混乱.来自他们的有价值的信息:Brian Hayes 在Beautiful Code中的章节涵盖了共线性测试功能的设计空间 - 有用的背景.文森特的回答有助于改善这一点.Hayes建议只测试x或y坐标中的一个; 原来代码代替了.andif a.x != b.x else


我认为这个答案明显优于目前接受的答案.

4> Sridhar Iyer..:

这是另一种方法:

让我们假设两个点是A(x1,y1)和B(x2,y2)

通过这些点的直线方程是(x-x1)/(y-y1)=(x2-x1)/(y2-y1)..(只是等于斜率)

如果出现以下情况,C点(x3,y3)将位于A和B之间:

x3,y3满足上述等式.

x3位于x1和x2之间,y3位于y1和y2之间(平凡检查)



5> vincent..:

段的长度并不重要,因此不需要使用平方根,应该避免使用,因为我们可能会失去一些精度.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Segment:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def is_between(self, c):
        # Check if slope of a to c is the same as a to b ;
        # that is, when moving from a.x to c.x, c.y must be proportionally
        # increased than it takes to get from a.x to b.x .

        # Then, c.x must be between a.x and b.x, and c.y must be between a.y and b.y.
        # => c is after a and before b, or the opposite
        # that is, the absolute value of cmp(a, b) + cmp(b, c) is either 0 ( 1 + -1 )
        #    or 1 ( c == a or c == b)

        a, b = self.a, self.b             

        return ((b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y) and 
                abs(cmp(a.x, c.x) + cmp(b.x, c.x)) <= 1 and
                abs(cmp(a.y, c.y) + cmp(b.y, c.y)) <= 1)

一些随机的使用示例:

a = Point(0,0)
b = Point(50,100)
c = Point(25,50)
d = Point(0,8)

print Segment(a,b).is_between(c)
print Segment(a,b).is_between(d)

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有