[CSharpTips]C# 判断多边形边界曲线顺/逆时针
C# 判断多边形边界曲线顺/逆时针
一个List<Point>表示的不规则多边形判断是顺时针还是逆时针
自己想到的方法是选择三个连续的点ABC利用向量积,AB*AC小于零顺时针,大于零逆时针,不过要先排除三个点在一条直线上且中间点为凹点的情况
后来找到个大佬用Green公式判断,简单高效,感叹数学的神奇
代码贴在下面
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; namespace ClockDirectionCheck { class Program { static void Main(string[] args) { List<Point> points = new List<Point>(); points.Add(new Point(0, 0)); points.Add(new Point(0, 100)); points.Add(new Point(100, 100)); points.Add(new Point(50, 90)); points.Add(new Point(100, 75)); points.Add(new Point(50, 60)); points.Add(new Point(100, 45)); points.Add(new Point(50, 30)); points.Add(new Point(100, 0)); Console.WriteLine("================顺序=================="); Console.WriteLine("==SelfFunction=="); if (GetClockDirection(points)) { Console.WriteLine("顺时针"); } else { Console.WriteLine("逆时针"); } Console.WriteLine("=====Green====="); if (Green(points)) { Console.WriteLine("顺时针"); } else { Console.WriteLine("逆时针"); } Console.WriteLine("================逆序=================="); points.Reverse(); Console.WriteLine("==SelfFunctio==="); if (GetClockDirection(points)) { Console.WriteLine("顺时针"); } else { Console.WriteLine("逆时针"); } Console.WriteLine("=====Green====="); if (Green(points)) { Console.WriteLine("顺时针"); } else { Console.WriteLine("逆时针"); } Console.WriteLine("================End=================="); Console.ReadLine(); } /// <summary> /// 排除不在一条直线上,排除凹点后用向量积判断 /// </summary> /// <param name="points"></param> /// <returns></returns> private static bool GetClockDirection(List<Point> points) { bool result = false; ; for (int i = 0; i < points.Count() - 2; i++) { //判断是否在一条直线上 if (points[i].X == points[i + 1].X && points[i + 1].X == points[i + 2].X) continue; if (points[i].Y == points[i + 1].Y && points[i + 1].Y == points[i + 2].Y) continue; //检测中间点是否是凹点 var newPoints = new List<Point>(points); newPoints.Remove(points[i + 1]); Geometry geometry = Geometry.Parse(GetPathByPoinits(newPoints)); if (geometry.FillContains(new System.Windows.Point() { X = points[i + 1].X, Y = points[i + 1].Y })) { continue; } //求向量积AC*AB 小于零顺时针 大于零逆时针 if (VectorCross(points[i], points[i + 1], points[i + 2]) < 0) { result = true; break; } else { result = false; break; } } return result; } //获取Path路径 private static string GetPathByPoinits(List<Point> points) { if (points == null || points.Count() == 0) { return ""; } string result = "M"; foreach (var item in points) { result += item.X + "," + item.Y + " "; } result += "Z"; return result; } public struct Point { public double X; public double Y; public Point(double x, double y) { X = x; Y = y; } } private static double VectorCross(Point p1, Point p2, Point p3) { Vector vectorP1 = new Vector(p1.X, p1.Y); Vector vectorP2 = new Vector(p2.X, p2.Y); Vector vectorP3 = new Vector(p3.X, p3.Y); Vector vectorP1P2 = Vector.Subtract(vectorP2, vectorP1); Vector vectorP1P3 = Vector.Subtract(vectorP3, vectorP1); return Vector.CrossProduct(vectorP1P2, vectorP1P3); } //格林公式 private static bool Green(List<Point> points) { double d = 0; for (int i = 0; i < points.Count - 1; i++) { d += -0.5 * (points[i + 1].Y + points[i].Y) * (points[i + 1].X - points[i].X); } if (d > 0) return false; else return true; } } }
参考:https://blog.csdn.net/henuyh/article/details/80378818