看一个点是否在一条线上(矢量)

时间:2014-11-10 17:39:50

标签: c++ algorithm math

enter image description here

我的程序中目前有以下行。我有两个其他整数变量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!
    }
}

它似乎没有工作,或者这个想法是什么?

5 个答案:

答案 0 :(得分:4)

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

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

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!
}

如果你的输入是整数,小到足以使乘法不会溢出,那么就根本不需要浮点运算。

答案 1 :(得分:1)

解决此问题的有效方法是使用三角形的有符号区域。当点{x1,y1}{x2,y2}{x,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}

答案 2 :(得分:0)

首先,您需要计算线的等式。然后看看这个等式是否适用于你拥有的x和y的值。要计算线的方程,需要计算出它与y轴交叉的位置以及它的梯度。方程将是y = mx + c的形式,其中m是梯度,c是截距&#39; (该线穿过y轴)。

答案 3 :(得分:0)

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

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 应该是一些小数字,取决于您期望的准确度。)

答案 4 :(得分:0)

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

您可能希望首先检查完美的水平线或垂直线。在这些情况下,您只需检查x是否介于x1x2之间(或yy1之间的y2垂直)。< / p>

否则,您可以在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