C++性能关键场景下,检查线段包含点的最快方法是什么?
性能关键场景下,线段包含点的高效检测方法
我知道网上有很多关于如何检查线段是否包含点的讨论,但我的核心问题是:在性能敏感的应用中,哪种方法效率最高?
查阅各类技术资料后,我总结出三种通用方法:
基于距离计算的方法
float distance(Vector2 a, Vector2 b) { return std::sqrtf(std::powf((a.x - b.x), 2.f) + std::powf((a.y - b.y), 2.f)); } bool containsPoint(Vector2 lineP, Vector2 lineQ, Vector2 point) { return distance(lineP, point) + distance(point,lineQ) == distance(lineP, lineQ); }
我直接排除了这种方法,三次平方根运算的开销太大,完全不符合性能要求。
基于斜率计算的方法
bool containsPoint(Vector2 lineP, Vector2 lineQ, Vector2 point) { float slope = (lineP.y - lineQ.y) / (lineP.x - lineQ.x); float c = lineP.y - lineP.x * slope; float minX = std::min(lineP.x, lineQ.x); float maxX = (minX == lineP.x) ? lineQ.x : lineP.x; return point.x * slope + c == point.y && point.x >= minX && point.x <= maxX; }
这是我最初想到的实现,但不确定它的性能是不是最优的。而且这个方法存在明显缺陷:当线段垂直于X轴时,lineP.x - lineQ.x为0,会触发除以0的错误,实际使用时必须添加额外的分支判断,这会进一步降低性能。
基于叉乘与点乘的方法
bool containsPoint(Vector2 lineP, Vector2 lineQ, Vector2 point) { float crossproduct = (point.y - lineP.y) * (lineQ.x - lineP.x) - (point.x - lineP.x) * (lineQ.y - lineP.y); if (fabs(crossproduct) > std::numeric_limits<float>::epsilon()) { return false; } float dotproduct = (point.x - lineP.x) * (lineQ.x - lineP.x) + (point.y - lineP.y)*(lineQ.y - lineP.y); if (dotproduct < 0.f) { return false; } float squaredlengthba = (lineQ.x - lineP.x)*(lineQ.x - lineP.x) + (lineQ.y - lineP.y)*(lineQ.y - lineP.y); if (dotproduct > squaredlengthba) { return false; } return true; }
这个方法代码量比斜率法多,但完全不需要除法操作——众所周知除法的运算速度大概只有乘法的1/10,所以理论上这是更高效的方案。它通过叉乘判断点是否落在直线上,再通过点乘判断点是否处于线段的范围内,既没有浮点运算的隐患,逻辑也更严谨。
除此之外,有没有比这种方法更快的实现?
内容的提问来源于stack exchange,提问作者JensB
相关产品推荐
相关产品推荐

