前段时间有写过一个计算多边形角度的代码,这里给它整理整理,留给自己也送给萌新。
看左下图,这是一个多环的多边形,一个外环(内部为多边形内部区域),一个内环(外部为多边形内部区域),同时多边形中任意一个角不等于零角(等于 0° 的角)或周角(等于 360° 的角)。注意:本文下文所讨论的多边形求角度不包含零角和周角。
现在我们要求 ∠ABC 和 ∠DEF 的大小。那咋算唻?
1. 内积计算夹角
给它加上坐标系(坐标是自己配的,计算出的角度值不一定准确,但不影响角度大小的关系), 如右上图。角度采用向量的内积来求。
以上面的 ∠ABC 为例,数学计算公式如下。
于是乎,有:
角度计算代码如下:
public struct CxPoint { public CxPoint(double x, double y) { X = x; Y = y; } public double X; public double Y; } /// <summary> /// 计算三点角度,p1-p2-p3为沿环方向的三个连续顶点,其中p2为角点。计算结果范围 0° - 180°,-1为无效值 /// </summary> private static double CalculationAngle(CxPoint p1, CxPoint p2, CxPoint p3) { //Cos(Angle) = a•b/(|a|*|b|) double x1 = p1.X - p2.X, y1 = p1.Y - p2.Y; //向量 a double x2 = p3.X - p2.X, y2 = p3.Y - p2.Y; //向量 b //零向量,存在共点 if (x1 == 0 && y1 == 0) return -1; if (x2 == 0 && y2 == 0) return -1; double v = x1 * x2 + y1 * y2; //向量内积 a•b double val = Math.Sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)); //a,b模长乘积 |a|*|b| double CosAngle = v / val; //求出来的值可能略小于 -1 或者略大于 1,此时 Angle 等于 NaN double Angle = Math.Acos(CosAngle) * 180.0 / 3.14159265358979; //两向量夹角,0-180 if (System.Double.IsNaN(Angle)) { if (v > 0) return 0; else return 180; } else { if (Angle > 180) return 180; else if (Angle < 0) return 0; else return Angle; } }