[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

posted @ 2022-11-08 10:57  xiaoshuye  阅读(357)  评论(0编辑  收藏  举报