查看一个点是不是位于一条线上(向量)
Posted
技术标签:
【中文标题】查看一个点是不是位于一条线上(向量)【英文标题】:See if a point lies on a line(vector)查看一个点是否位于一条线上(向量) 【发布时间】:2014-11-10 17:39:50 【问题描述】:我的程序中目前有以下行。我还有另外两个整数变量,x
和 y
。
我想看看这个新点(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,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
与线段的边界。
【讨论】:
【参考方案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
是否介于x1
和x2
之间(或y
是否介于y1
和y2
之间)。
否则,您可以在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
【讨论】:
以上是关于查看一个点是不是位于一条线上(向量)的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 41