1. 概述
判斷點是否在線段上的算法非常簡單,有很多種實現方式,總結一下我自己的實現。
2. 詳論
個人認爲通過向量計算的方式是比較好的,因爲可以保證在二維和三維的情況都成立。判斷空間中點P是否在線段P1P2上,算法思想是分成兩部分:
- 計算\(\vec{P1P2}\)與\(\vec{P1P}\)的向量叉積,可以判斷是否存在一條直線上。原理是向量叉積的模(長度)表示兩個向量組成的平面四邊形的面積,如果叉積的模爲0,說明兩者共線,無法組成平行四邊形。
- 計算向量點積,點積的幾何意義是一個向量向另外一個向量的投影;如果滿足如下公式,說明是在兩個端點之間:
具體的代碼實現如下所示:
#include <Eigen/Eigen>
#include <iostream>
using namespace Eigen;
using namespace std;
using LineSegment = Vector2d[2];
const double epsilon = 0.000000001;
//判斷點在線段上
bool PointInLine(const Vector2d& point, const LineSegment& lineSegment) {
Vector3d P1P2;
P1P2 << lineSegment[1] - lineSegment[0], 0;
Vector3d P1P;
P1P << point - lineSegment[0], 0;
if (fabs((P1P2.cross(P1P)).norm()) > epsilon) {
return false;
}
double dotProduct = P1P2.dot(P1P);
if (dotProduct > 0 && dotProduct < P1P2.squaredNorm()) {
return true;
}
return false;
}
int main() {
// LineSegment lineSegment;
// lineSegment[0] = Vector2d(0, 0);
// lineSegment[1] = Vector2d(50, 100);
// Vector2d c(25, 50);
// Vector2d d(0, 8);
LineSegment lineSegment;
lineSegment[0] = Vector2d(2.6, 1.5);
lineSegment[1] = Vector2d(24.5, 80.6);
Vector2d ld = lineSegment[1] - lineSegment[0];
Vector2d c = lineSegment[0] + 0.46 * ld;
Vector2d d(0, 8);
cout << PointInLine(c, lineSegment) << endl;
// cout << PointInLine(d, lineSegment) << endl;
}
說明一下代碼實現:
- 使用了Eigen中的矢量類,其實自己使用其他庫的矢量類或者自己實現也是可以的。
- 內置浮點型的精度有限,因此設置epsilon作爲容差。
- 由於是使用向量計算,因而是可以拓展到三維空間中使用的。