查看一个点是不是位于一条线上(向量)

Posted

技术标签:

【中文标题】查看一个点是不是位于一条线上(向量)【英文标题】:See if a point lies on a line(vector)查看一个点是否位于一条线上(向量) 【发布时间】:2014-11-10 17:39:50 【问题描述】:

我的程序中目前有以下行。我还有另外两个整数变量,xy

我想看看这个新点(x, y) 是否在这条线上。我一直在看以下线程:

Given a start and end point, and a distance, calculate a point along a line

我想出了以下几点:

if(x >= x1 && x <= x2 && (y >= y1 && y <= y2 || y <= y1 && y >= y2))

    float vx = x2 - x1;
    float vy = y2 - y1;
    float mag = sqrt(vx*vx + vy*vy);
    // need to get the unit vector (direction)
    float dvx = vx/mag; // this would be the unit vector (direction) x for the line
    float dvy = vy/mag; // this would be the unit vector (direction) y for the line

    float vcx = x - x1;
    float vcy = y - y1;
    float magc = sqrt(vcx*vcx + vcy*vcy);
    // need to get the unit vector (direction)
    float dvcx = vcx/magc; // this would be the unit vector (direction) x for the point
    float dvcy = vcy/magc; // this would be the unit vector (direction) y for the point

    // I was thinking of comparing the direction of the two vectors, if they are the same then the point must lie on the line?
    if(dvcx == dvx && dvcy == dvy)
    
        // the point is on the line!
    

它似乎不起作用,还是这个想法很糟糕?

【问题讨论】:

它是二维的,为什么不简单地将 (x,y) 放在从 (x1,y1) 和 (x2,y2) 获得的直线方程中? (x, y) 是一个点(如标题所示)还是一个向量(如问题所示)?这个问题似乎只有当它是一个点时才真正有意义,但也许你在谈论由两个向量定义的线是否相交? 首先,请说明您的条件/假设。如果您正在处理浮点数,则必须考虑浮点数的不准确性。将数学直接转化为公式是行不通的。 @JerryCoffin 一点!为不一致的符号道歉。 见this 【参考方案1】:

浮点数的精度有限,因此您会从计算中得到舍入误差,从而导致在数学上应该相等的值最终会略有不同。

您需要与较小的误差容差进行比较:

if (std::abs(dvcx-dvx) < tolerance && std::abs(dvcy-dvy) < tolerance)

    // the point is (more or less) on the line!

困难的部分是选择公差。如果您不能接受任何错误,那么您将需要使用固定精度浮点值以外的其他值 - 可能是整数,并重新安排计算以避免除法和其他不精确的操作。

在任何情况下,您都可以更简单地执行此操作,无需平方根之类的任何东西。你想知道这两个向量是否平行;如果向量积为零,或者等效地,如果它们具有相等的切线,则它们是。所以你只需要

if (vx * vcy == vy * vcx)  // might still need a tolerance for floating-point

    // the point is on the line!

如果您的输入是整数,足够小以至于乘法不会溢出,那么根本不需要浮点运算。

【讨论】:

详细来说,x1、y1和x2、y2都是整数! @KarlMorrison:在这种情况下,您应该能够完全避免浮点恶作剧。请参阅我的更新答案。【参考方案2】:

解决此问题的一种有效方法是使用三角形的有符号面积。当由点x1,y1x2,y2x,y 创建的三角形的带符号区域接近于零时,您可以认为x,y 在线。正如其他人所提到的,如果您使用的是浮点值,那么选择一个好的容差值是其中的一个重要部分。

bool isPointOnLine (xy p1, xy p2, xy p3) // returns true if p3 is on line p1, p2
    
    xy va = p1 - p2;
    xy vb = p3 - p2;
    area = va.x * vb.y - va.y * vb.x;
    if (abs (area) < tolerance)
        return true;
    return false;
    

这会让您知道x,y 是否在线,但它不会确定x,y 是否包含在线段中。为此,您还需要检查 x,y 与线段的边界。

【讨论】:

【参考方案3】:

首先你需要计算你的直线方程。然后看看这个等式是否适用于你拥有的 x 和 y 的值。要计算直线的方程,您需要计算出它与 y 轴相交的位置以及它的梯度。方程的形式为 y=mx+c,其中 m 是梯度,c 是“截距”(直线与 y 轴相交处)。

【讨论】:

【参考方案4】:

对于浮点值,不要使用 == 而是测试小的差异:

if (fabs(dvcx-dvx) < delta && fabs(dvcy-dvy) < delta)

另外,你不需要单位向量,只需要切线:

float originalTangent = (y2 - y1) / (x2 - x1);
float newTangent = (y - y1) / (x - x1);
if (fabs(newTangent - originalTangent) < delta)  ... 

delta 应该是一个很小的数字,取决于您期望的准确度。)

【讨论】:

【参考方案5】:

鉴于 (x, y) 实际上是一个点,这项工作似乎比你做的要简单一些。

您可能希望从检查完美的水平线或垂直线开始。在这些情况下,您只需检查x 是否介于x1x2 之间(或y 是否介于y1y2 之间)。

否则,您可以在x 上使用线性插值,看看它是否为您提供了正确的 y 值(在一些可能的舍入公差范围内)。为此,您可以执行以下操作:

slope = (y2-y1)/(x2-x1);
if (abs(slope * (x - x1) - y) < tolerance)
    // (x,y) is on the line
else
    // (x,y) isn't on the line

【讨论】:

以上是关于查看一个点是不是位于一条线上(向量)的主要内容,如果未能解决你的问题,请参考以下文章

检查 3 个点是不是在同一条线上

C# arcengine 获取一条线上的点

python 找到一条点到一条线上最近点的距离

Educational Codeforces Round 41

Educational Codeforces Round 41(已补D,E)

python 世界杯在一条线上。