點在多邊形內判斷是圖形學、GIS、遊戲碰撞的基礎運算。射線法(Ray Casting)以 O(n) 時間、O(1) 空間成為通用標準:從點向任意方向發射射線,統計與多邊形邊相交次數,奇數在內、偶數在外。
若射線與多邊形邊相交奇數次,點在內部;偶數次在外部。需處理邊界情況:點在頂點、點在邊上、射線穿過頂點。
// 返回 1 內部,0 外部,-1 邊界
int pointInPolygon(int n, const Point* poly, Point p) {
int inside = 0;
for (int i = 0, j = n - 1; i < n; j = i++) {
const Point *pi = &poly[i], *pj = &poly[j];
// 檢查點是否在邊上
if (onSegment(*pi, *pj, p)) return -1;
// 射線相交判斷:(yi > y) != (yj > y) 且 x < 交點x
if ((pi->y > p.y) != (pj->y > p.y)) {
double x_intersect = (double)(pj->x - pi->x) * (p.y - pi->y) / (pj->y - pi->y) + pi->x;
if (p.x < x_intersect) inside = !inside;
}
}
return inside;
}
// 輔助:點在線段上(含端點)
int onSegment(Point a, Point b, Point p) {
return cross(b - a, p - a) == 0 && dot(p - a, p - b) <= 0;
}
| 變體 | 核心優化 | 適用場景 |
|---|---|---|
| 整數座標版 | 避免浮點,用交叉乘積判斷相交 | 嵌入式、定點運算、像素座標 |
| 浮點座標版 | 通用、精度高、代碼簡潔 | GIS、CAD、通用圖形庫 |
| SSE/AVX 向量化版 | 並行處理 4/8 條邊,提升 3-4 倍吞吐 | 大規模多邊形批量檢測、遊戲物理引擎 |
(yi > y) != (yj > y) 條件天然去重,避免雙計數。射線法是點在多邊形判斷的「瑞士軍刀」:原理簡單、實現靈活、擴展性強。工程中首選成熟庫(CGAL、Clipper、JTS),自行實現時務必建立完整邊界測試用例集。