原理解析:利用叉积 Z 分量判断凸凹性
在计算几何中,判断一个多边形的顶点是凸(Convex)还是凹(Concave),最常用的方法是利用向量的叉积(Cross Product)。
这段代码的核心逻辑如下:
double crossZ = Vector3d.CrossProduct(ePrev, eNext).Z; bool isConvex = crossZ > 0;
1. 向量叉积的几何意义
在三维空间中,两个向量 $\vec{A}$ 和 $\vec{B}$ 的叉积结果是一个新的向量 $\vec{C}$: $$ \vec{C} = \vec{A} \times \vec{B} $$
这个新向量 $\vec{C}$ 有两个重要特性:
- 方向:垂直于 $\vec{A}$ 和 $\vec{B}$ 所在的平面。
- 模长:等于 $\vec{A}$ 和 $\vec{B}$ 构成的平行四边形的面积。
对于二维平面(XY平面)上的向量,它们的 Z 坐标为 0。 设 $\vec{A} = (x_1, y_1, 0)$,$\vec{B} = (x_2, y_2, 0)$。 它们的叉积结果 $\vec{C}$ 将只有 Z 分量:
$$ \vec{C} = (0, 0, x_1 y_2 - x_2 y_1) $$
我们关注的就是这个 Z 分量 $(x_1 y_2 - x_2 y_1)$ 的正负号。
2. 右手定则 (Right-Hand Rule)
判断 Z 分量正负的直观方法是使用右手定则:
- 伸出右手,四指指向第一个向量 $\vec{A}$ (即代码中的 `ePrev`) 的方向。
- 将四指弯曲向第二个向量 $\vec{B}$ (即代码中的 `eNext`) 的方向。
- 大拇指的指向就是叉积结果的方向(Z轴方向)。
| Z 分量符号 | 大拇指指向 | 旋转方向 (从 A 到 B) | 几何含义 (左/右转) |
|---|---|---|---|
| 正 (+) | 指向屏幕外 (Z+) | 逆时针 (CCW) | 向左转 (Left Turn) |
| 负 (-) | 指向屏幕内 (Z-) | 顺时针 (CW) | 向右转 (Right Turn) |
| 零 (0) | 无 | 共线 | 直线,无转弯 |
3. 结合代码的具体分析
在你的代码中:
- ePrev:是进入当前顶点的向量(Previous Point → Current Point)。
- eNext:是离开当前顶点的向量(Current Point → Next Point)。
想象你沿着多边形的边界行走:
- 你先沿着 `ePrev` 走。
- 到了当前点,你需要转向 `eNext` 的方向继续走。
判定逻辑: 如果 `crossZ > 0`,根据右手定则,这意味着从 `ePrev` 到 `eNext` 是逆时针旋转。 在二维平面行进中,逆时针旋转等同于向左转。
4. 为什么 "向左转" 代表 "凸角"?
这取决于多边形的点的排列顺序(Winding Order)。
通常在 GIS 和图形学算法中,定义一个实心多边形的标准是:
- 逆时针顺序 (Counter-Clockwise, CCW) 排列顶点。
- 这样定义后,多边形的内部始终位于边界行进方向的左侧。
在此前提下:
- 凸角 (Convex):行进时向左转(角度 < 180°)。此时 `CrossZ > 0`。
- 凹角 (Concave):行进时向右转(角度 > 180°,向内凹陷)。此时 `CrossZ < 0`。
注意:如果你的多边形是顺时针 (CW) 排列的(例如某些图形库如 GDI+ 的默认行为),那么逻辑会完全反过来:`CrossZ < 0` 才是凸角。
代码中的 `bool isConvex = crossZ > 0;` 隐含假设了输入数据 `input` 是逆时针排列的。
5. 总结
| 代码 | 数学含义 | 物理动作 | 形状特征 (CCW多边形) |
| crossZ > 0 | 逆时针旋转 | 向左拐弯 | 凸 (Convex) |
| crossZ < 0 | 顺时针旋转 | 向右拐弯 | 凹 (Concave) |
这段代码利用叉积的 Z 分量,快速判断了在当前顶点处,路径是向左拐还是向右拐,从而识别出需要处理的“凸”尖角。

评论