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


93

假设您有一个二维平面,上面有2个点(分别称为a和b),每个点由x整数和ay整数表示。

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

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


4
我在这些答案中看到了很多length = sqrt(x)的东西。它们可能会起作用,但是速度并不快。考虑使用长度平方;如果您只是相互比较平方的长度值,则不会损失准确性,并且可以将对sqrt()的缓慢调用保存下来。
ojrac

1
点c是否也由2个整数表示?如果是这样,那么您是否想知道c是否恰好沿着a和b之间的真实直线?还是位于a和b之间的直线的栅格近似上?这是一个重要的澄清。
RobS

在此处提出了类似的问题:stackoverflow.com/q/31346862/1914034,其中提供了一种解决方案,该解决方案需要与线路保持缓冲距离
低于雷达


1
对未来读者的警告:相当多的答案是不正确或不完整的。水平线和垂直线通常不起作用。
Stefnotch

Answers:


127

按照Darius Bacon的说法,检查(ba)和(ca)的叉积是否为0,以指示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

5
-epsilon < crossproduct < epsilon and min(a.x, b.x) <= c.x <= max(a.x, b.x) and min(a.y, b.y) <= c.y <= max(a.y, b.y)足够了,不是吗?
jfs

9
叉积的绝对值是由三个点形成的三角形面积的两倍(符号表示边的第三点),因此恕我直言,您应使用与两个端点之间的距离成比例的epsilon。
巴特

2
您能告诉我们为什么整数不起作用吗?如果epsilon检查由“!= 0”代替,我看不到问题。
西里尔·卡

2
是的,多余的括号只是一个错字。有人说了4年过去了。:)
Cyrille Ka

4
您应该重命名a,b,c以便更清楚地指出哪些是段终点,哪些是查询点。
Craig Gidney

48

这是我的处理方式:

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)

7
这是一个优雅的解决方案。
Paul D. Eden

6
唯一的问题是数值稳定性-取数字的差等容易丢失精度。
乔纳森·莱夫勒

26
-epsilon < (distance(a, c) + distance(c, b) - distance(a, b)) < epsilon
jfs

1
@jfs是什么意思?epsilon的用途是什么?
霓虹灯Warge

3
@NeonWarge:sqrt()返回一个浮点数。==在大多数情况下,对浮动而言是错误的事情math.isclose()可以代替使用。有没有math.isclose()在2008年,因此我提供了明确的不平等epsilonabs_tolmath.isclose()说吧)。
jfs

35

检查b-a和的叉积c-a是否为0:表示所有点是共线的。如果是,请检查c的坐标是否在a和之间b。使用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


由于范围检查更快,因此最好先进行范围检查,然后再在边界框中检查共线。
Grant M

1
对于a == b!= c的情况,函数is_on(a,b,c)是错误的。在这种情况下,即使c不与从a到b的线段相交,它也将返回true。
MikkoVirkkilä15年

@SuperFlux,我只是尝试运行它,然后得到了False。
Darius Bacon

2
我认为该答案明显优于当前接受的答案。
瑞克

1
collinear(a,b,c)通过相等性测试浮点数。它不应该使用ε/公差吗?
jwezorek

7

这是另一种方法:

  • 假设两个点分别是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之间(平凡检查)

这没有考虑到舍入误差(坐标的不精确性)。
巴特

我认为这是个正确的主意,但细节不足(我们如何在实践中检查该方程式?)且有一些错误:最后一个y3应该是y2。
大流士培根

@Darius:修正了该错字
Harley Holcombe

7

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

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)

1
如果cx或cy浮动,则第一个==输入is_between()可能会失败(顺便说一下,这是变相的叉积)。
jfs

添加到is_between()a, b = self.a, self.b
jfs

如果所有三个点都相同(没错,恕我直言),它将返回true;但是如果恰好两个点相同,则返回false-定义中间性的方式非常不一致。我在答案中张贴了一个替代方法。
大流士培根

通过另一个cmp技巧解决了该问题,但是此代码开始出现气味;-)
森特

5

这是另一种处理方法,使用C ++提供的代码。给定l1和l2这两个点,将它们之间的线段表示为

l1 + A(l2 - l1)

其中0 <= A <=1。如果您对此感兴趣,而不仅仅是将其用于此问题,则称为行的矢量表示。我们可以拆分出x和y分量,得到:

x = l1.x + A(l2.x - l1.x)
y = l1.y + A(l2.y - l1.y)

取一个点(x,y)并将其x和y分量代入这两个表达式中以求解A。如果两个表达式中A的解都相等且0 <= A <= 1,则该点在线上。求解A需要除法,在某些特殊情况下,当线段是水平或垂直时,需要进行处理以使除以零而停止。最终的解决方案如下:

// Vec2 is a simple x/y struct - it could very well be named Point for this use

bool isBetween(double a, double b, double c) {
    // return if c is between a and b
    double larger = (a >= b) ? a : b;
    double smaller = (a != larger) ? a : b;

    return c <= larger && c >= smaller;
}

bool pointOnLine(Vec2<double> p, Vec2<double> l1, Vec2<double> l2) {
    if(l2.x - l1.x == 0) return isBetween(l1.y, l2.y, p.y); // vertical line
    if(l2.y - l1.y == 0) return isBetween(l1.x, l2.x, p.x); // horizontal line

    double Ax = (p.x - l1.x) / (l2.x - l1.x);
    double Ay = (p.y - l1.y) / (l2.y - l1.y);

    // We want Ax == Ay, so check if the difference is very small (floating
    // point comparison is fun!)

    return fabs(Ax - Ay) < 0.000001 && Ax >= 0.0 && Ax <= 1.0;
}

4

使用更几何的方法,计算以下距离:

ab = sqrt((a.x-b.x)**2 + (a.y-b.y)**2)
ac = sqrt((a.x-c.x)**2 + (a.y-c.y)**2)
bc = sqrt((b.x-c.x)**2 + (b.y-c.y)**2)

并测试ac + bc是否等于ab

is_on_segment = abs(ac + bc - ab) < EPSILON

这是因为存在三种可能性:

  • 3个点组成一个三角形=> ac + bc> ab
  • 它们是共线的,并且cab段之外=> ac + bc> ab
  • 它们是共线的,并且cab片段内=> ac + bc = ab

正如乔纳森·莱夫勒(Jonathan Leffler)在另一条评论中提到的那样,这存在一些数字问题,其他方法(例如跨产品)可以避免。我在答案中链接到的章节进行了说明。
大流士培根

3

好的,关于线性代数(向量的叉积)的提及很多,这在实数空间(即连续点或浮点)中有效,但是问题特别指出,这两个点都用整数表示,因此叉积不是正确的虽然可以给出一个近似解。

正确的解决方案是在两个点之间使用Bresenham的直线算法,并查看第三个点是否为直线上的点之一。如果这些点之间的距离足够远,以至于无法计算出算法(对于这种情况,它必须非常大),那么我相信您可以四处挖掘并找到优化方案。


它解决了如何在两个任意点之间的二维整数空间中绘制一条线及其数学上的正确性。如果第三个点是该线上的点之一,那么根据定义,该点位于这两个点之间。
cletus

1
不,布雷森纳姆的线算法解决了如何在二维整数空间中创建线段的近似值。从原始海报的消息中我看不到这是关于栅格化的问题。
西里尔·卡

“比方说,您有一个二维平面,上面有2个点(分别称为a和b),每个点用x INTEGER和ay INTEGER表示。” (我加强调)。
cletus

1
我认为布雷森纳姆(Bresenham)的“线算法”(Line Algorithm)给一条线提供了壁橱整数,然后可以用来绘制该线。他们可能不在网上。例如,如果对于(0,0)到(11,13),该算法将给出一个要绘制的数字像素,但除端点外没有整数点,因为11和13是互质的。
Grant M

对于实空间(ℝ×ℝ)正确的解怎么可能对于整数空间(ℕ×ℕ)不正确,如ℕ∈ℝ。还是您的意思是:“不是……的最佳选择”而不是“不正确?”?
Ideogram

2

(ca)和(ba)之间的标量积必须等于其长度的乘积(这意味着向量(ca)和(ba)对齐且方向相同)。此外,(ca)的长度必须小于或等于(ba)的长度。伪代码:

# epsilon = small constant

def isBetween(a, b, c):
    lengthca2  = (c.x - a.x)*(c.x - a.x) + (c.y - a.y)*(c.y - a.y)
    lengthba2  = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
    if lengthca2 > lengthba2: return False
    dotproduct = (c.x - a.x)*(b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if dotproduct < 0.0: return False
    if abs(dotproduct*dotproduct - lengthca2*lengthba2) > epsilon: return False 
    return True

最后一个条件不应该更像:ABS(product-lengthca * lengthba)<epsilon吗?
乔纳森·莱夫勒

您不应该在比较平方长度吗?应避免平方根。此外,如果由于溢出而不可避免,则可以使用math.hypot代替math.sqrt(对参数进行适当的更改)。
大流士培根

我也想知道那个ε。你能解释一下吗?当然,如果必须处理浮点数,则必须谨慎进行比较,但是我不清楚为什么epsilon可以使这种特定的比较更加准确。
大流士培根

我同意。这个问题有好几个答案,这个很好。但是此代码需要修改为不使用sqrt,并且最后的比较已修复。
Cyrille Ka

@Jonathan:的确,使用Abs的代码更加熟悉和优雅。谢谢。
Federico A. Ramponi's

2

我需要在html5画布中使用javascript的javascript,以检测用户光标是在特定行上方还是附近。因此,我将Darius Bacon给出的答案修改为coffeescript:

is_on = (a,b,c) ->
    # "Return true if 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 withincheck(a,b,c))

withincheck = (a,b,c) ->
    if a[0] != b[0]
        within(a[0],c[0],b[0]) 
    else 
        within(a[1],c[1],b[1])

collinear = (a,b,c) ->
    # "Return true if a, b, and c all lie on the same line."
    ((b[0]-a[0])*(c[1]-a[1]) < (c[0]-a[0])*(b[1]-a[1]) + 1000) and ((b[0]-a[0])*(c[1]-a[1]) > (c[0]-a[0])*(b[1]-a[1]) - 1000)

within = (p,q,r) ->
    # "Return true if q is between p and r (inclusive)."
    p <= q <= r or r <= q <= p

2

您可以使用楔形和点积:

def dot(v,w): return v.x*w.x + v.y*w.y
def wedge(v,w): return v.x*w.y - v.y*w.x

def is_between(a,b,c):
   v = a - b
   w = b - c
   return wedge(v,w) == 0 and dot(v,w) > 0

1

这是我在学校做的事情。我忘记了为什么这不是一个好主意。

编辑:

@Darius Bacon:引用了一本“美丽的代码”书,其中包含了以下代码为什么不是一个好主意的解释。

#!/usr/bin/env python
from __future__ import division

epsilon = 1e-6

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

class LineSegment:
    """
    >>> ls = LineSegment(Point(0,0), Point(2,4))
    >>> Point(1, 2) in ls
    True
    >>> Point(.5, 1) in ls
    True
    >>> Point(.5, 1.1) in ls
    False
    >>> Point(-1, -2) in ls
    False
    >>> Point(.1, 0.20000001) in ls
    True
    >>> Point(.1, 0.2001) in ls
    False
    >>> ls = LineSegment(Point(1, 1), Point(3, 5))
    >>> Point(2, 3) in ls
    True
    >>> Point(1.5, 2) in ls
    True
    >>> Point(0, -1) in ls
    False
    >>> ls = LineSegment(Point(1, 2), Point(1, 10))
    >>> Point(1, 6) in ls
    True
    >>> Point(1, 1) in ls
    False
    >>> Point(2, 6) in ls 
    False
    >>> ls = LineSegment(Point(-1, 10), Point(5, 10))
    >>> Point(3, 10) in ls
    True
    >>> Point(6, 10) in ls
    False
    >>> Point(5, 10) in ls
    True
    >>> Point(3, 11) in ls
    False
    """
    def __init__(self, a, b):
        if a.x > b.x:
            a, b = b, a
        (self.x0, self.y0, self.x1, self.y1) = (a.x, a.y, b.x, b.y)
        self.slope = (self.y1 - self.y0) / (self.x1 - self.x0) if self.x1 != self.x0 else None

    def __contains__(self, c):
        return (self.x0 <= c.x <= self.x1 and
                min(self.y0, self.y1) <= c.y <= max(self.y0, self.y1) and
                (not self.slope or -epsilon < (c.y - self.y(c.x)) < epsilon))

    def y(self, x):        
        return self.slope * (x - self.x0) + self.y0

if __name__ == '__main__':
    import  doctest
    doctest.testmod()

1

线段(ab)上的任何点(其中ab是向量)都可以表示为两个向量ab线性组合

换句话说,如果c位于线段(ab)上:

c = ma + (1 - m)b, where 0 <= m <= 1

求解m,得到:

m = (c.x - b.x)/(a.x - b.x) = (c.y - b.y)/(a.y - b.y)

因此,我们的测试变为(在Python中):

def is_on(a, b, c):
    """Is c on the line segment ab?"""

    def _is_zero( val ):
        return -epsilon < val < epsilon

    x1 = a.x - b.x
    x2 = c.x - b.x
    y1 = a.y - b.y
    y2 = c.y - b.y

    if _is_zero(x1) and _is_zero(y1):
        # a and b are the same point:
        # so check that c is the same as a and b
        return _is_zero(x2) and _is_zero(y2)

    if _is_zero(x1):
        # a and b are on same vertical line
        m2 = y2 * 1.0 / y1
        return _is_zero(x2) and 0 <= m2 <= 1
    elif _is_zero(y1):
        # a and b are on same horizontal line
        m1 = x2 * 1.0 / x1
        return _is_zero(y2) and 0 <= m1 <= 1
    else:
        m1 = x2 * 1.0 / x1
        if m1 < 0 or m1 > 1:
            return False
        m2 = y2 * 1.0 / y1
        return _is_zero(m2 - m1)

1

c#从http://www.faqs.org/faqs/graphics/algorithms-faq/- >主题1.02:如何找到点到线的距离?

Boolean Contains(PointF from, PointF to, PointF pt, double epsilon)
        {

            double segmentLengthSqr = (to.X - from.X) * (to.X - from.X) + (to.Y - from.Y) * (to.Y - from.Y);
            double r = ((pt.X - from.X) * (to.X - from.X) + (pt.Y - from.Y) * (to.Y - from.Y)) / segmentLengthSqr;
            if(r<0 || r>1) return false;
            double sl = ((from.Y - pt.Y) * (to.X - from.X) - (from.X - pt.X) * (to.Y - from.Y)) / System.Math.Sqrt(segmentLengthSqr);
            return -epsilon <= sl && sl <= epsilon;
        }

在大多数其他方法中,避免精度问题的正确方法。也比大多数其他方法效率更高。
罗宾·戴维斯

1

这是一些对我有用的Java代码:

boolean liesOnSegment(Coordinate a, Coordinate b, Coordinate  c) {

    double dotProduct = (c.x - a.x) * (c.x - b.x) + (c.y - a.y) * (c.y - b.y);
    if (dotProduct < 0) return true;
    return false;
}

1
dotProduct只能说明对齐方式。您的代码不完整!使用a(0,0),b(4,0),c(1,1),您的点积=(1-0)*(1-4)+(1-0)*(1-0)=- 3 + 1 = -3
user43968 '18

0

仅确保斜率相同且点在其他点之间又如何呢?

给定点(x1,y1)和(x2,y2)(x2> x1)和候选点(a,b)

如果(b-y1)/(a-x1)=(y2-y2)/(x2-x1)并且x1 <a <x2

然后(a,b)必须位于(x1,y1)和(x2,y2)之间


当某些坐标接近或相同时,疯狂的浮点精度问题又如何呢?
罗宾·戴维斯

计算机的浮点运算不好。在计算机中,没有无限连续可调的值。因此,如果您使用的是浮点数,则必须建立定义并使用一些小的epsilon值作为行列式,比该epsilon更近的任何两个点都应视为同一点。确定IS在同一条直线上以及到端点的距离相同的点。如果您的候选点在该计算点的epsilon内,则称其相同。
查尔斯·布雷塔纳

我的观点是,当您实际在代码中实现它时,由于精度问题,该答案不可用。所以没有人应该使用它。数学测试的一个很好的答案。但是,计算机科学课程中的竞争失败。我来这里是为了寻找点积方法(正确)。所以我想我会花点时间在这个线程中标记出许多不正确的答案,这样其他熟悉正确解决方案的人就不会试图使用它们。
罗宾·戴维斯

您对由于计算机无法在一行上表示每个可能的实数而引起的问题是正确的。您不正确地认为任何解决方案(包括点积法)都不会受到这些问题的影响。任何解决方案都可能遭受这些问题的困扰。除非您对可接受的epsilon进行了一些折衷,否则精确地在线上的点(但其坐标不能用ieee浮点二进制表示法表示)也将无法通过点积测试,因为计算机将无法正确表示该点的坐标在某种程度上。
查尔斯·布雷塔纳

0

使用Vector2D类的C#答案

public static bool IsOnSegment(this Segment2D @this, Point2D c, double tolerance)
{
     var distanceSquared = tolerance*tolerance;
     // Start of segment to test point vector
     var v = new Vector2D( @this.P0, c ).To3D();
     // Segment vector
     var s = new Vector2D( @this.P0, @this.P1 ).To3D();
     // Dot product of s
     var ss = s*s;
     // k is the scalar we multiply s by to get the projection of c onto s
     // where we assume s is an infinte line
     var k = v*s/ss;
     // Convert our tolerance to the units of the scalar quanity k
     var kd = tolerance / Math.Sqrt( ss );
     // Check that the projection is within the bounds
     if (k <= -kd || k >= (1+kd))
     {
        return false;
     }
     // Find the projection point
     var p = k*s;
     // Find the vector between test point and it's projection
     var vp = (v - p);
     // Check the distance is within tolerance.
     return vp * vp < distanceSquared;
}

注意

s * s

是C#中通过运算符重载得到的段向量的点积

关键是要利用点在无限线上的投影,并观察投影的标量可以简单地告诉我们投影是否在线段上。我们可以调整标量的范围以使用模糊容差。

如果投影在边界内,我们只需测试从点到投影的距离是否在边界内。

相对于叉积法的好处是公差具有有意义的值。


0

这是我在Unity中使用C#的解决方案。

private bool _isPointOnLine( Vector2 ptLineStart, Vector2 ptLineEnd, Vector2 ptPoint )
{
    bool bRes = false;
    if((Mathf.Approximately(ptPoint.x, ptLineStart.x) || Mathf.Approximately(ptPoint.x, ptLineEnd.x)))
    {
        if(ptPoint.y > ptLineStart.y && ptPoint.y < ptLineEnd.y)
        {
            bRes = true;
        }
    }
    else if((Mathf.Approximately(ptPoint.y, ptLineStart.y) || Mathf.Approximately(ptPoint.y, ptLineEnd.y)))
    {
        if(ptPoint.x > ptLineStart.x && ptPoint.x < ptLineEnd.x)
        {
            bRes = true;
        }
    }
    return bRes;
}

看起来这段代码仅适用于垂直和水平线段。如果ptLineStart为(0,0),ptLineEnd为(2,2)而ptPoint为(1、1)怎么办?
vac

0

C#版本的Jules的答案:

public static double CalcDistanceBetween2Points(double x1, double y1, double x2, double y2)
{
    return Math.Sqrt(Math.Pow (x1-x2, 2) + Math.Pow (y1-y2, 2));
}

public static bool PointLinesOnLine (double x, double y, double x1, double y1, double x2, double y2, double allowedDistanceDifference)
{
    double dist1 = CalcDistanceBetween2Points(x, y, x1, y1);
    double dist2 = CalcDistanceBetween2Points(x, y, x2, y2);
    double dist3 = CalcDistanceBetween2Points(x1, y1, x2, y2);
    return Math.Abs(dist3 - (dist1 + dist2)) <= allowedDistanceDifference;
}

0

您可以通过用点坐标求解该线段的线方程来实现,您将知道该点是否在线上,然后检查线段的边界以知道该线段是在线段的内部还是外部。您可以应用一些阈值,因为它恰好位于空间中最有可能由浮点值定义的某个位置,并且您不得达到确切的阈值。PHP示例

function getLineDefinition($p1=array(0,0), $p2=array(0,0)){
    
    $k = ($p1[1]-$p2[1])/($p1[0]-$p2[0]);
    $q = $p1[1]-$k*$p1[0];
    
    return array($k, $q);
    
}

function isPointOnLineSegment($line=array(array(0,0),array(0,0)), $pt=array(0,0)){
    
    // GET THE LINE DEFINITION y = k.x + q AS array(k, q) 
    $def = getLineDefinition($line[0], $line[1]);
    
    // use the line definition to find y for the x of your point
    $y = $def[0]*$pt[0]+$def[1];

    $yMin = min($line[0][1], $line[1][1]);
    $yMax = max($line[0][1], $line[1][1]);

    // exclude y values that are outside this segments bounds
    if($y>$yMax || $y<$yMin) return false;
    
    // calculate the difference of your points y value from the reference value calculated from lines definition 
    // in ideal cases this would equal 0 but we are dealing with floating point values so we need some threshold value not to lose results
    // this is up to you to fine tune
    $diff = abs($pt[1]-$y);
    
    $thr = 0.000001;
    
    return $diff<=$thr;
    
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.