如何判断一个点是否属于某条线?

发布于 2024-07-23 05:40:45 字数 47 浏览 8 评论 0原文

如何判断一个点是否属于某条线?

如果可能的话,示例值得赞赏。

How can I tell if a point belongs to a certain line?

Examples are appreciated, if possible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

后知后觉 2024-07-30 05:40:45

在最简单的形式中,只需将坐标代入直线方程并检查是否相等。

给定:

Point p (X=4, Y=5)
Line l (Slope=1, YIntersect=1)

代入 X 和 Y:

   Y = Slope * X + YIntersect
=> 5 = 1 * 4 + 1
=> 5 = 5

所以是的,点在线上。

如果您的线以 (X1,Y1),(X2,Y2) 形式表示,那么您可以使用以下方法计算斜率:

 Slope = (y1 - y2) / (x1-x2)

然后用以下方法获取 Y 相交:

 YIntersect = - Slope * X1 + Y1;

编辑:我修复了 Y 相交(已为 X1 / Y1 ...)

您必须检查 x1 - x2 是否不是 0。 如果是,则检查该点是否在线上只需检查点中的 Y 值是否等于 x1x2 即可。 另外,检查点的 X 是否不是“x1”或“x2”。

In the simplest form, just plug the coordinates into the line equation and check for equality.

Given:

Point p (X=4, Y=5)
Line l (Slope=1, YIntersect=1)

Plug in X and Y:

   Y = Slope * X + YIntersect
=> 5 = 1 * 4 + 1
=> 5 = 5

So yes, the point is on the line.

If your lines are represented in (X1,Y1),(X2,Y2) form, then you can calculate slope with:

 Slope = (y1 - y2) / (x1-x2)

And then get the Y-Intersect with this:

 YIntersect = - Slope * X1 + Y1;

Edit: I fixed the Y-Intersect (which has been X1 / Y1 ...)

You'll have to check that x1 - x2 is not 0. If it is, then checking if the point is on the line is a simple matter of checking if the Y value in your point is equal to either x1 or x2. Also, check that the X of the point is not 'x1' or 'x2'.

度的依靠╰つ 2024-07-30 05:40:45

我刚刚编写了一个函数,它可以处理一些额外的要求,因为我在绘图应用程序中使用了此检查:

  • 模糊性 - 由于该函数用于通过单击线条来选择线条,因此必须存在一些出错空间。
  • 该线有一个终点和一个起点,没有无限的线。
  • 必须处理垂直和水平直线, (x2 - x1) == 0 会导致其他答案中除以零。
private const double SELECTION_FUZZINESS = 3;

internal override bool ContainsPoint(Point point)
{
    LineGeometry lineGeo = geometry as LineGeometry;
    Point leftPoint;
    Point rightPoint;

    // Normalize start/end to left right to make the offset calc simpler.
    if (lineGeo.StartPoint.X <= lineGeo.EndPoint.X)
    {
        leftPoint   = lineGeo.StartPoint;
        rightPoint  = lineGeo.EndPoint;
    }
    else
    {
        leftPoint   = lineGeo.EndPoint;
        rightPoint  = lineGeo.StartPoint;
    }

    // If point is out of bounds, no need to do further checks.                  
    if (point.X + SELECTION_FUZZINESS < leftPoint.X || rightPoint.X < point.X - SELECTION_FUZZINESS)
        return false;
    else if (point.Y + SELECTION_FUZZINESS < Math.Min(leftPoint.Y, rightPoint.Y) || Math.Max(leftPoint.Y, rightPoint.Y) < point.Y - SELECTION_FUZZINESS)
        return false;

    double deltaX = rightPoint.X - leftPoint.X;
    double deltaY = rightPoint.Y - leftPoint.Y;

    // If the line is straight, the earlier boundary check is enough to determine that the point is on the line.
    // Also prevents division by zero exceptions.
    if (deltaX == 0 || deltaY == 0) 
        return true;

    double slope        = deltaY / deltaX;
    double offset       = leftPoint.Y - leftPoint.X * slope;
    double calculatedY  = point.X * slope + offset;

    // Check calculated Y matches the points Y coord with some easing.
    bool lineContains = point.Y - SELECTION_FUZZINESS <= calculatedY && calculatedY <= point.Y + SELECTION_FUZZINESS;

    return lineContains;            
}

I just wrote an function which handles a few extra requirements since I use this check in a drawing application:

  • Fuzziness - There must be some room for error since the function is used to select lines by clicking on them.
  • The line got an EndPoint and a StartPoint, no infinite lines.
  • Must handle straight vertical and horizontal lines, (x2 - x1) == 0 causes division by zero in the other answers.
private const double SELECTION_FUZZINESS = 3;

internal override bool ContainsPoint(Point point)
{
    LineGeometry lineGeo = geometry as LineGeometry;
    Point leftPoint;
    Point rightPoint;

    // Normalize start/end to left right to make the offset calc simpler.
    if (lineGeo.StartPoint.X <= lineGeo.EndPoint.X)
    {
        leftPoint   = lineGeo.StartPoint;
        rightPoint  = lineGeo.EndPoint;
    }
    else
    {
        leftPoint   = lineGeo.EndPoint;
        rightPoint  = lineGeo.StartPoint;
    }

    // If point is out of bounds, no need to do further checks.                  
    if (point.X + SELECTION_FUZZINESS < leftPoint.X || rightPoint.X < point.X - SELECTION_FUZZINESS)
        return false;
    else if (point.Y + SELECTION_FUZZINESS < Math.Min(leftPoint.Y, rightPoint.Y) || Math.Max(leftPoint.Y, rightPoint.Y) < point.Y - SELECTION_FUZZINESS)
        return false;

    double deltaX = rightPoint.X - leftPoint.X;
    double deltaY = rightPoint.Y - leftPoint.Y;

    // If the line is straight, the earlier boundary check is enough to determine that the point is on the line.
    // Also prevents division by zero exceptions.
    if (deltaX == 0 || deltaY == 0) 
        return true;

    double slope        = deltaY / deltaX;
    double offset       = leftPoint.Y - leftPoint.X * slope;
    double calculatedY  = point.X * slope + offset;

    // Check calculated Y matches the points Y coord with some easing.
    bool lineContains = point.Y - SELECTION_FUZZINESS <= calculatedY && calculatedY <= point.Y + SELECTION_FUZZINESS;

    return lineContains;            
}
多情癖 2024-07-30 05:40:45

确定点 R = (rx, ry) 是否位于点 P = (px, py) 和 Q = (qx, qy) 的连线上的最佳方法是检查矩阵的行列式是否为

{{qx - px, qy - py}, {rx - px, ry - py}},

(qx - px) ) * (ry - py) - (qy - py) * (rx - px) 接近于 0。与其他发布的解决方案相比,该解决方案有几个相关优点:首先,它不需要垂直线的特殊情况,其次,它不需要不除(通常是一个缓慢的操作),第三,当线几乎但不完全垂直时,它不会触发不良的浮点行为。

The best way to determine if a point R = (rx, ry) lies on the line connecting points P = (px, py) and Q = (qx, qy) is to check whether the determinant of the matrix

{{qx - px, qy - py}, {rx - px, ry - py}},

namely (qx - px) * (ry - py) - (qy - py) * (rx - px) is close to 0. This solution has several related advantages over the others posted: first, it requires no special case for vertical lines, second, it doesn't divide (usually a slow operation), third, it doesn't trigger bad floating-point behavior when the line is almost, but not quite vertical.

甜妞爱困 2024-07-30 05:40:45

给定直线 L0L1 上的两个点以及要测试的点 P

               (L1 - L0) * (P - L0)
n = (P - L0) - --------------------- (L1 - L0)
               (L1 - L0) * (L1 - L0)

向量n的范数是点P到通过L0L1的直线的距离。 如果该距离为零或足够小(在舍入误差的情况下),则该点位于直线上。

符号*表示点积。

示例

P = (5, 5)

L0 = (0, 10)
L1 = (20, -10)

L1 - L0 = (20, -20)
P  - L0 = (5, -5)

              (20, -20) * (5, -5)
n = (5, -5) - --------------------- (20, -20)
              (20, -20) * (20, -20)

              200
  = (5, -5) - --- (20, -20)
              800

  = (5, -5) - (5, -5)

  = (0, 0)

Given two points on the line L0 and L1 and the point to test P.

               (L1 - L0) * (P - L0)
n = (P - L0) - --------------------- (L1 - L0)
               (L1 - L0) * (L1 - L0)

The norm of the vector n is the distance of the point P from the line through L0 and L1. If this distance is zero or small enough (in the case of rounding errors), the point lies on the line.

The symbol * represents the dot product.

Example

P = (5, 5)

L0 = (0, 10)
L1 = (20, -10)

L1 - L0 = (20, -20)
P  - L0 = (5, -5)

              (20, -20) * (5, -5)
n = (5, -5) - --------------------- (20, -20)
              (20, -20) * (20, -20)

              200
  = (5, -5) - --- (20, -20)
              800

  = (5, -5) - (5, -5)

  = (0, 0)
萌吟 2024-07-30 05:40:45

我认为帕特里克·麦克唐纳先生提出了几乎正确的答案,这是对他答案的更正:

public bool IsOnLine(Point endPoint1, Point endPoint2, Point checkPoint)
{
    return (((double)checkPoint.Y - endPoint1.Y)) / ((double)(checkPoint.X - endPoint1.X))
        == ((double)(endPoint2.Y - endPoint1.Y)) / ((double)(endPoint2.X - endPoint1.X));
}

当然还有很多其他正确答案,尤其是乔什先生,但我发现这是最好的答案。

谢谢大家。

I think Mr.Patrick McDonald put the nearly correct answer and this is the correction of his answer:

public bool IsOnLine(Point endPoint1, Point endPoint2, Point checkPoint)
{
    return (((double)checkPoint.Y - endPoint1.Y)) / ((double)(checkPoint.X - endPoint1.X))
        == ((double)(endPoint2.Y - endPoint1.Y)) / ((double)(endPoint2.X - endPoint1.X));
}

and of course there are many other correct answers especially Mr.Josh but i found this is the best one.

Thankx for evryone.

浮光之海 2024-07-30 05:40:45
y = m * x + c

这是直线方程。 x& y 是坐标。 每条线的特征在于其斜率 (m ) 及其与 y 轴的相交位置 (c)。

所以给定 m & c 对于直线,您可以通过检查方程是否满足 x = x1 和 y = y1 来确定点 (x1, y1) 是否在线上

y = m * x + c

This is the equation of a line. x & y are the co-ordinates. Each line is characterized by its slope (m ) and where it intersects the y-axis (c).

So given m & c for a line, you can determine if the point (x1, y1) is on the line by checking if the equation holds for x = x1 and y = y1

三月梨花 2024-07-30 05:40:45

二维线通常使用两个变量 x 和 y 中的方程来表示,这是一个众所周知的方程

y-y1 = (y1-y2)/(x1-x2) (x-x1)

现在想象你的 GDI+ 线是从 (0,0) 到 (100, 100) 绘制的,那么 m=(0 -100)/(0-100) = 1 因此你的线的方程是 y-0=1*(x-0) => y=x

现在我们有了相关直线的方程,很容易测试一个点是否属于这条直线。 当您代入 x=x3 和 y=y3 时,如果给定点 (x3, y3) 满足直线方程,则该点属于该直线。 例如,点 (10, 10) 属于这条线,因为 10=10,但 (10,12) 不属于这条线,因为 12 != 10。

注意:对于垂直线,斜率 (m) 值为无限,但对于这种特殊情况,您可以直接使用垂直线方程 x=c,其中 c = x1 = x2。

尽管我不得不说我不确定这是否是最有效的方法。 当我有更多时间时,我会尝试找到更有效的方法。

希望这可以帮助。

A 2D line is generally represented using an equation in two variables x and y here is a well known equation

y-y1 = (y1-y2)/(x1-x2) (x-x1)

Now imagine your GDI+ line is drawn from (0,0) to (100, 100) then the value of m=(0-100)/(0-100) = 1 thus the equation for your line is y-0=1*(x-0) => y=x

Now that we have an equation for the line in question its easy to test if a point belongs to this line. A given point (x3, y3) belongs to this line if it satisfies the line equation when you substitute x=x3 and y=y3. For example the point (10, 10) belongs to this line since 10=10 but (10,12) does not belong to this line since 12 != 10.

NOTE: For a vertical line the value of the slope (m) is infinite but for this special case you may use the equation for a vertical line directly x=c where c = x1 = x2.

Though I have to say I am not sure if this is the most efficient way of doing this. I will try and find a more efficient way when I have some more time on hand.

Hope this helps.

无畏 2024-07-30 05:40:45

如果您有一条由其端点定义的线

PointF pt1, pt2;

,并且您有一个想要检查的点

PointF checkPoint;

,那么您可以按如下方式定义一个函数:

bool IsOnLine(PointF endPoint1, PointF endPoint2, PointF checkPoint) 
{
    return (checkPoint.Y - endPoint1.Y) / (endPoint2.Y - endPoint1.Y)
        == (checkPoint.X - endPoint1.X) / (endPoint2.X - endPoint1.X);
}

并按如下方式调用它:

if (IsOnLine(pt1, pt2, checkPoint) {
    // Is on line
}

不过,您将需要检查是否被零除。

If you have a line defined by its endpoints

PointF pt1, pt2;

and you have a point that you want to check

PointF checkPoint;

then you could define a function as follows:

bool IsOnLine(PointF endPoint1, PointF endPoint2, PointF checkPoint) 
{
    return (checkPoint.Y - endPoint1.Y) / (endPoint2.Y - endPoint1.Y)
        == (checkPoint.X - endPoint1.X) / (endPoint2.X - endPoint1.X);
}

and call it as follows:

if (IsOnLine(pt1, pt2, checkPoint) {
    // Is on line
}

You will need to check for division by zero though.

不美如何 2024-07-30 05:40:45

直线方程为:

y = mx + c

因此,如果点 (a,b) 满足该方程,则该点位于该直线上,即 b = ma + c

Equation of the line is:

y = mx + c

So a point(a,b) is on this line if it satisfies this equation i.e. b = ma + c

月亮坠入山谷 2024-07-30 05:40:45

作为 slope/y-intercept 方法的替代方法,我选择了使用 Math.Atan2 的方法:

// as an extension method
public static bool Intersects(this Vector2 v, LineSegment s) {
    //  check from line segment start perspective
    var reference = Math.Atan2(s.Start.Y - s.End.Y, s.Start.X - s.End.X);
    var aTanTest = Math.Atan2(s.Start.Y - v.Y, s.Start.X - v.X);

    //  check from line segment end perspective
    if (reference == aTanTest) {
        reference = Math.Atan2(s.End.Y - s.Start.Y, s.End.X - s.Start.X);
        aTanTest = Math.Atan2(s.End.Y - v.Y, s.End.X - v.X);
    }

    return reference == aTanTest;
}

第一个检查 reference 确定 arcTan线段的起点到终点。
然后从起点角度,确定向量v的arcTan。

如果这些值相等,我们从终点的角度进行检查。

简单,可以处理水平、垂直以及介于两者之间的所有其他情况。

As an alternative to the slope/y-intercept method, I chose this approach using Math.Atan2:

// as an extension method
public static bool Intersects(this Vector2 v, LineSegment s) {
    //  check from line segment start perspective
    var reference = Math.Atan2(s.Start.Y - s.End.Y, s.Start.X - s.End.X);
    var aTanTest = Math.Atan2(s.Start.Y - v.Y, s.Start.X - v.X);

    //  check from line segment end perspective
    if (reference == aTanTest) {
        reference = Math.Atan2(s.End.Y - s.Start.Y, s.End.X - s.Start.X);
        aTanTest = Math.Atan2(s.End.Y - v.Y, s.End.X - v.X);
    }

    return reference == aTanTest;
}

The first check reference determines the arcTan from the start point of the line segment to it's end-point.
Then from the start point perspective, we determine the arcTan to the vector v.

If those values are equal, we check from the perspective of the end-point.

Simple and handles horizontal, vertical and all else in between.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文