using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Geometry;
using GeoAPI.Operation.Buffer;
using KGIS.Framework.AE;
using NetTopologySuite.IO;
using NetTopologySuite.Operation.Buffer;
namespace Kingo.PluginServiceInterface.Helper
{
    /// 
    /// 狭长图形检测工具类(静态类)
    /// 功能:检测多边形中是否存在狭长区域(如长条状、细带状图斑)
    /// 核心算法思路:通过分析多边形环的顶点分布,识别局部密集点对,构建子多边形并通过紧凑度指标判断是否为狭长区域
    /// 
    public static class PolygonNarrowAreaChecker
    {
        /// 
        /// 检测多边形中的局部狭长区域
        /// 
        /// 待检测的输入多边形(支持带内环的复杂多边形)
        /// 距离阈值(单位:与坐标系一致,默认1):用于判断两个顶点是否"过近",作为狭长区域的初步筛选条件
        /// 检测到的狭长区域多边形列表(每个元素为一个狭长子多边形)
        public static List CheckLocalNarrowAreas(IPolygon polygon, double distanceThreshold = 1)
        {
            List narrowAreas = new List(); // 存储检测到的狭长区域
            //var xxx = GeometryConvertHelper.ConvertIGeoemtryToWKT(polygon);
            string sNarrow = ISNarrow(polygon);
            if (!string.IsNullOrEmpty(sNarrow))
            {
                #region 删除图形中的重复点(首位点除外)
                IGeometryCollection geomColl = polygon as IGeometryCollection;
                // 遍历所有子环(外环和内环)
                for (int i = 0; i < geomColl.GeometryCount; i++)
                {
                    IGeometry subGeom = geomColl.get_Geometry(i);
                    IRing ring = subGeom as IRing; // 环是闭合的线(IRing 继承自 IPolyline)
                    if (ring == null) continue;
                    // 处理当前环的重复点
                    RemoveDuplicatePointsInRing(ring);
                }
                #endregion
                IGeometryCollection geometryCollection = polygon as IGeometryCollection;// 将多边形转换为几何集合(用于遍历内部环)
                if (geometryCollection == null) return narrowAreas; // 非几何集合类型直接返回空列表
                for (int ringIndex = 0; ringIndex < geometryCollection.GeometryCount; ringIndex++)// 遍历多边形的所有环(外环+内环)
                {
                    IRing ring = geometryCollection.get_Geometry(ringIndex) as IRing; // 获取当前环
                    if (ring == null) continue; // 非环类型跳过
                    IPointCollection points = ring as IPointCollection;// 将环转换为点集合(用于获取顶点坐标)
                    int pointCount = points.PointCount; // 环的总顶点数
                    bool isClosed = ring.IsClosed; // 判断环是否闭合(多边形环通常需闭合)
                    int effectivePointCount = isClosed ? pointCount - 1 : pointCount; // 有效顶点数(闭合环需排除最后一个重复点)
                                                                                      // 【步骤1】预处理环的顶点坐标:转换为结构体数组(提升计算性能)和IPoint对象数组(用于几何构建)
                    var (ringPoints, ringPointsIPoint) = PreprocessRingPoints(points, effectivePointCount); if (ringPoints == null) continue; // 预处理失败时跳过当前环
                    HashSet<(double X, double Y)> usedPoints = new HashSet<(double X, double Y)>();
                    // 预计算所有线段的AABB(索引k对应线段k→k+1)
                    var segmentAABBs = new (double MinX, double MaxX, double MinY, double MaxY)[effectivePointCount - 1];
                    for (int idx = 0; idx < effectivePointCount - 1; idx++)
                    {
                        IPoint pStart = ringPointsIPoint[idx];
                        IPoint pEnd = ringPointsIPoint[idx + 1];
                        segmentAABBs[idx] = (
                            MinX: Math.Min(pStart.X, pEnd.X),
                            MaxX: Math.Max(pStart.X, pEnd.X),
                            MinY: Math.Min(pStart.Y, pEnd.Y),
                            MaxY: Math.Max(pStart.Y, pEnd.Y)
                        );
                    }
                    // 遍历所有可能的线段对(需优化遍历范围,避免O(n²)复杂度)
                    for (int k = 0; k < effectivePointCount - 1; k++)
                    {
                        IPoint p1 = ringPointsIPoint[k];
                        IPoint p2 = ringPointsIPoint[k + 1];
                        // 检查p1/p2是否已被使用(通过坐标判断)
                        if (usedPoints.Contains((p1.X, p1.Y)) || usedPoints.Contains((p2.X, p2.Y))) continue;
                        // 获取当前线段k的AABB
                        var aabbK = segmentAABBs[k];
                        for (int m = k + 2; m < effectivePointCount - 1; m++) // 跳过相邻线段
                        {
                            IPoint p3 = ringPointsIPoint[m];
                            IPoint p4 = ringPointsIPoint[m + 1];
                            // 检查p3/p4是否已被使用
                            if (usedPoints.Contains((p3.X, p3.Y)) || usedPoints.Contains((p4.X, p4.Y))) continue;
                            // 获取对比线段m的AABB
                            var aabbM = segmentAABBs[m];
                            // AABB预筛选:判断两线段的包围盒是否可能相交
                            // 条件:x轴投影重叠且y轴投影重叠
                            double expandDistance = 1;//相当于外扩
                            bool xOverlap = (aabbK.MaxX + expandDistance) >= (aabbM.MinX - expandDistance) &&
                    (aabbK.MinX - expandDistance) <= (aabbM.MaxX + expandDistance);
                            bool yOverlap = (aabbK.MaxY + expandDistance) >= (aabbM.MinY - expandDistance) &&
                    (aabbK.MinY - expandDistance) <= (aabbM.MaxY + expandDistance);
                            if (!xOverlap || !yOverlap) continue; // AABB不重叠,直接跳过后续复杂计算
                                                                  // 判断线段是否共点(如p1=p3, p2=p4等)
                            if (ArePointsEqual(p1, p3) || ArePointsEqual(p1, p4) || ArePointsEqual(p2, p3) || ArePointsEqual(p2, p4)) continue;
                            // 计算线段(p1,p2)和(p3,p4)的距离(仅保留AABB重叠的情况)
                            Vector2D vecAB = CalculateVector(p1, p2);
                            Vector2D vecCD = CalculateVector(p3, p4);
                            bool isSameDirection = AreVectorsSameDirection(vecAB, vecCD, 0.01);
                            if (isSameDirection) continue;
                            var vangle = CalculateAngle(vecAB, vecCD);
                            if (vangle < 25 || vangle > 155) continue;
                            double distance = CalculateSegmentDistance(p1, p2, p3, p4);
//                            var xxx1 = $@"
//{GeometryConvertHelper.ConvertIGeoemtryToWKT(p1)}
//{GeometryConvertHelper.ConvertIGeoemtryToWKT(p2)}
//{GeometryConvertHelper.ConvertIGeoemtryToWKT(p3)}
//{GeometryConvertHelper.ConvertIGeoemtryToWKT(p4)}";
                            if (distance < 0.1)
                            {
                                IPoint iIntersection = GetExtendedLineIntersection(p1, p2, p3, p4); //两条线段的交点
                                if (iIntersection != null)
                                {
                                    double p1distance = PointToSegmentDistance(p1, p3, p4);
                                    double p2distance = PointToSegmentDistance(p2, p3, p4);
                                    double p3distance = PointToSegmentDistance(p3, p1, p2);
                                    double p4distance = PointToSegmentDistance(p4, p1, p2);
                                    int pindex_k = p1distance > p2distance ? k + 1 : k;
                                    int pindex_m = p3distance > p4distance ? m + 1 : m;
                                    double iIntersection12 = PointToSegmentDistance(iIntersection, p1, p2);
                                    double iIntersection34 = PointToSegmentDistance(iIntersection, p3, p4);
                                    IPoint point = null;
                                    if (iIntersection34 < iIntersection12)
                                    {
                                        point = p1distance > p2distance ? p2 : p1;
                                    }
                                    else
                                    {
                                        point = p3distance > p4distance ? p4 : p3;
                                    }
                                    try
                                    {
                                        IPolyline polyline1 = new PolylineClass();
                                        polyline1.FromPoint = iIntersection;
                                        polyline1.ToPoint = point;
                                        polyline1.SpatialReference = polygon.SpatialReference;
                                        if (polyline1.Length < 0.1)
                                        {
                                            polyline1 = getExtendLine(polyline1, 3, 0.01);
                                        }
                                        var CutGeometryresult = FeatureAPI.CutGeometry(polygon, polyline1);
                                        Marshal.ReleaseComObject(polyline1);
                                        if (CutGeometryresult != null && CutGeometryresult.Count == 2)
                                        {
                                            foreach (var item in CutGeometryresult)
                                            {
                                                sNarrow = ISNarrow(item);
                                                if (sNarrow == "POLYGON EMPTY")
                                                {
                                                    List pointList = null;
                                                    var angle = SharpAngle.GetMinAngle1(item, ref pointList, false);
                                                    if (angle < 10) continue;
                                                    if (isThreeSides(item)) continue;
                                                    narrowAreas.Add(item as IPolygon);
                                                    usedPoints.Add((p1.X, p1.Y));
                                                    usedPoints.Add((p2.X, p2.Y));
                                                    usedPoints.Add((p3.X, p3.Y));
                                                    usedPoints.Add((p4.X, p4.Y));
                                                }
                                                else if (!string.IsNullOrEmpty(sNarrow))
                                                {
                                                    narrowAreas = CheckLocalNarrowAreas(item as IPolygon);
                                                }
                                            }
                                        }
                                        else if (CutGeometryresult != null && CutGeometryresult.Count == 1)
                                        {
                                            continue;
                                            //IGeometry geo = CutGeometryresult[0];
                                            //if (geo != null && !geo.IsEmpty)
                                            //{
                                            //    sNarrow = ISNarrow(geo);
                                            //    if (!string.IsNullOrEmpty(sNarrow))
                                            //    {
                                            //        List pointList = null;
                                            //        var angle = SharpAngle.GetMinAngle1(geo, ref pointList, false);
                                            //        if (angle < 10) continue;
                                            //        narrowAreas.Add(geo as IPolygon);
                                            //        usedPoints.Add((p1.X, p1.Y));
                                            //        usedPoints.Add((p2.X, p2.Y));
                                            //        usedPoints.Add((p3.X, p3.Y));
                                            //        usedPoints.Add((p4.X, p4.Y));
                                            //        continue;
                                            //    }
                                            //}
                                            //else continue;
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }
                return narrowAreas;
            }
            return new List();
        }
        private static IPoint GetExtendedLineIntersection(IPoint start1, IPoint end1, IPoint start2, IPoint end2)
        {
            // 创建原始线段
            IPolyline polyline1 = new PolylineClass();
            polyline1.FromPoint = start1;
            polyline1.ToPoint = end1;
            // 延长线段(假设 getExtendLine 可能返回包含中间点的多段线)
            IPolyline extendedPolyline1 = getExtendLine(polyline1, 3, 1);
            // 提取延长后的起点和终点,重建为仅含两点的线段
            IPolyline simplifiedLine1 = new PolylineClass();
            simplifiedLine1.FromPoint = extendedPolyline1.FromPoint; // 延长后的起点
            simplifiedLine1.ToPoint = extendedPolyline1.ToPoint;     // 延长后的终点
            // 对第二条线段执行相同操作
            IPolyline polyline2 = new PolylineClass();
            polyline2.FromPoint = start2;
            polyline2.ToPoint = end2;
            IPolyline extendedPolyline2 = getExtendLine(polyline2, 3, 1);
            IPolyline simplifiedLine2 = new PolylineClass();
            simplifiedLine2.FromPoint = extendedPolyline2.FromPoint;
            simplifiedLine2.ToPoint = extendedPolyline2.ToPoint;
            // 计算简化后线段的交点
            ITopologicalOperator topoOp = simplifiedLine1 as ITopologicalOperator;
            IGeometry intersection = topoOp.Intersect(simplifiedLine2, esriGeometryDimension.esriGeometry0Dimension);
            // 处理交点结果(与原逻辑一致)
            if (intersection != null && intersection.GeometryType == esriGeometryType.esriGeometryPoint)
            {
                return intersection as IPoint;
            }
            else if (intersection.GeometryType == esriGeometryType.esriGeometryMultipoint)
            {
                IPointCollection points = intersection as IPointCollection;
                if (points.PointCount > 0)
                    return points.get_Point(0);
            }
            return null;
        }
        /// 
        /// 延长线段
        /// 
        /// 传入去的线
        /// 模式,1为从FromPoint处延长,2为从ToPint处延长,3为两端延长
        /// 延长的距离
        /// 
        /// 创建人:懒羊羊
        public static IPolyline getExtendLine(IPolyline passLine, int mode, double dis)
        {
            IPointCollection pPointCol = passLine as IPointCollection;
            switch (mode)
            {
                case 1:
                    IPoint fromPoint = new PointClass();
                    passLine.QueryPoint(esriSegmentExtension.esriExtendAtFrom, -1 * dis, false, fromPoint);
                    pPointCol.InsertPoints(0, 1, ref fromPoint);
                    break;
                case 2:
                    IPoint endPoint = new PointClass();
                    object missing = Type.Missing;
                    passLine.QueryPoint(esriSegmentExtension.esriExtendAtTo, dis + passLine.Length, false, endPoint);
                    pPointCol.AddPoint(endPoint, ref missing, ref missing);
                    break;
                case 3:
                    IPoint fPoint = new PointClass();
                    IPoint ePoint = new PointClass();
                    object missing2 = Type.Missing;
                    passLine.QueryPoint(esriSegmentExtension.esriExtendAtFrom, -1 * dis, false, fPoint);
                    pPointCol.InsertPoints(0, 1, ref fPoint);
                    passLine.QueryPoint(esriSegmentExtension.esriExtendAtTo, dis + passLine.Length, false, ePoint);
                    pPointCol.AddPoint(ePoint, ref missing2, ref missing2);
                    break;
                default:
                    return pPointCol as IPolyline;
            }
            return pPointCol as IPolyline;
        }
        /// 
        /// 判断图形是否为三角形
        /// 
        /// 
        /// 
        private static bool isThreeSides(IGeometry geometry)
        {
            bool isThreeSides = false;
            try
            {
                if (geometry is IPolygon polygon1)
                {
                    IPointCollection pointCollection = polygon1 as IPointCollection;
                    int vertexCount = pointCollection.PointCount;
                    // 排除闭合多边形中重复的首尾顶点
                    IPoint startingpoint = pointCollection.get_Point(0);//起点
                    IPoint terminalpoint = pointCollection.get_Point(vertexCount - 1);//终点
                    if (polygon1.IsClosed && vertexCount > 1 && startingpoint.X == terminalpoint.X && startingpoint.Y == terminalpoint.Y)
                    {
                        vertexCount--;
                    }
                    isThreeSides = vertexCount == 3;
                }
            }
            catch (Exception ex)
            {
            }
            return isThreeSides;
        }
        /// 
        /// 判断两个点是否共点(考虑浮点精度误差)
        /// 
        /// 点1
        /// 点2
        /// 容差(默认1e-6,与坐标系单位一致)
        /// true:共点;false:不共点
        private static bool ArePointsEqual(IPoint p1, IPoint p2, double tolerance = 1e-6)
        {
            return Math.Abs(p1.X - p2.X) < tolerance && Math.Abs(p1.Y - p2.Y) < tolerance;
        }
        /// 
        /// 计算两条线段的最短距离(支持不相交、相交等场景)
        /// 
        /// 线段1的起点
        /// 线段1的终点
        /// 线段2的起点
        /// 线段2的终点
        /// 两条线段的最短距离
        private static double CalculateSegmentDistance(IPoint a1, IPoint a2, IPoint b1, IPoint b2)
        {
            // 向量定义:u为a线段方向,v为b线段方向,w为a1到b1的向量
            double ux = a2.X - a1.X;
            double uy = a2.Y - a1.Y;
            double vx = b2.X - b1.X;
            double vy = b2.Y - b1.Y;
            double wx = a1.X - b1.X;
            double wy = a1.Y - b1.Y;
            double a = ux * ux + uy * uy; // u·u(a线段长度平方)
            double b = ux * vx + uy * vy; // u·v(方向向量点积)
            double c = vx * vx + vy * vy; // v·v(b线段长度平方)
            double d = ux * wx + uy * wy; // u·w
            double e = vx * wx + vy * wy; // v·w
            double denominator = a * c - b * b; // 分母:(u·u)(v·v)-(u·v)²
            double t, s;
            // 情况1:线段平行或共线(分母为0)
            if (Math.Abs(denominator) < 1e-9)
            {
                t = 0; // a线段起点投影到b线段
                s = (b * t + e) / c; // 计算s(若c=0则b线段为点)
            }
            // 情况2:线段不平行,计算参数t和s
            else
            {
                t = (b * e - c * d) / denominator; // 投影参数t(a线段上)
                s = (a * e - b * d) / denominator; // 投影参数s(b线段上)
            }
            // 限制t和s在[0,1]范围内(超出则取端点)
            t = Math.Max(0, Math.Min(1, t));
            s = Math.Max(0, Math.Min(1, s));
            // 计算投影点距离
            double dx = (wx + ux * t - vx * s);
            double dy = (wy + uy * t - vy * s);
            return Math.Sqrt(dx * dx + dy * dy);
        }
        private static double PointToSegmentDistance(IPoint p, IPoint segStart, IPoint segEnd)
        {
            double segX = segEnd.X - segStart.X;
            double segY = segEnd.Y - segStart.Y;
            if (segX == 0 && segY == 0) // 线段为点
                return Math.Sqrt(Math.Pow(p.X - segStart.X, 2) + Math.Pow(p.Y - segStart.Y, 2));
            double t = ((p.X - segStart.X) * segX + (p.Y - segStart.Y) * segY) / (segX * segX + segY * segY);
            t = Math.Max(0, Math.Min(1, t)); // 投影参数限制在[0,1]
            double projX = segStart.X + t * segX;
            double projY = segStart.Y + t * segY;
            return Math.Sqrt(Math.Pow(p.X - projX, 2) + Math.Pow(p.Y - projY, 2));
        }
        /// 
        /// 预处理环的顶点坐标(结构体数组和IPoint数组)
        /// 
        /// 环的顶点集合(IPoint类型)
        /// 有效顶点数(闭合环需排除最后一个重复点)
        /// 元组:(顶点坐标结构体数组, IPoint对象数组);若异常则返回(null, null)
        private static ((double X, double Y)[], IPoint[]) PreprocessRingPoints(IPointCollection points, int effectivePointCount)
        {
            try
            {
                var ringPoints = new (double X, double Y)[effectivePointCount]; // 存储顶点坐标(结构体,轻量级)
                var ringPointsIPoint = new IPoint[effectivePointCount]; // 存储IPoint对象(用于几何操作)
                // 遍历有效顶点,填充两个数组
                for (int k = 0; k < effectivePointCount; k++)
                {
                    IPoint p = points.get_Point(k); // 获取第k个顶点
                    ringPoints[k] = (p.X, p.Y); // 转换为结构体
                    ringPointsIPoint[k] = p; // 保留IPoint对象
                }
                return (ringPoints, ringPointsIPoint);
            }
            catch (Exception ex)
            {
                // 异常处理:顶点读取失败时记录日志(实际开发中建议添加日志记录)
                return (null, null);
            }
        }
        /// 
        /// 判断两个向量是否同向
        /// 
        /// 向量1(如AB)
        /// 向量2(如CD)
        /// 浮点数精度容差(默认1e-6)
        /// 是否同向
        public static bool AreVectorsSameDirection(Vector2D vec1, Vector2D vec2, double tolerance = 1e-6)
        {
            // 1. 判断共线性:叉积的绝对值小于容差(考虑浮点数精度)
            double crossProduct = vec1.X * vec2.Y - vec2.X * vec1.Y;
            if (Math.Abs(crossProduct) > tolerance)
                return false; // 不共线,直接返回false
            // 2. 判断同向性:点积大于0(且向量模长不为0,避免零向量干扰)
            double dotProduct = vec1.X * vec2.X + vec1.Y * vec2.Y;
            double length1 = CalculateVectorLength(vec1);
            double length2 = CalculateVectorLength(vec2);
            // 模长为0的向量无方向(实际线段向量不会为零,此处为安全校验)
            if (length1 < tolerance || length2 < tolerance)
                return false;
            return dotProduct > tolerance; // 点积为正,方向相同
        }
        /// 
        /// 计算向量模长
        /// 
        public static double CalculateVectorLength(Vector2D vector)
        {
            return Math.Sqrt(Math.Pow(vector.X, 2) + Math.Pow(vector.Y, 2));
        }
        /// 
        /// 计算线段向量
        /// 
        /// 线段起点
        /// 线段终点
        /// 向量
        public static Vector2D CalculateVector(IPoint startPoint, IPoint endPoint)
        {
            if (startPoint == null || endPoint == null)
                throw new ArgumentNullException("点对象不能为空");
            return new Vector2D(
                endPoint.X - startPoint.X,
                endPoint.Y - startPoint.Y
            );
        }
        /// 
        /// 计算两个向量的夹角(角度制,0°~180°)
        /// 
        /// 向量1
        /// 向量2
        /// 精度容差(默认1e-6)
        /// 夹角角度(°)
        public static double CalculateAngle(Vector2D vec1, Vector2D vec2, double tolerance = 1e-6)
        {
            // 计算模长
            double len1 = CalculateVectorLength(vec1);
            double len2 = CalculateVectorLength(vec2);
            // 处理零向量(避免除零异常)
            if (len1 < tolerance || len2 < tolerance)
                throw new ArgumentException("向量模长不能为零");
            // 计算点积
            double dotProduct = vec1.X * vec2.X + vec1.Y * vec2.Y;
            // 计算cosθ(点积/(模长乘积))
            double cosTheta = dotProduct / (len1 * len2);
            // 修正数值精度误差(cosθ范围需在[-1, 1]内)
            cosTheta = Math.Max(Math.Min(cosTheta, 1.0), -1.0);
            // 计算弧度并转换为角度
            double radians = Math.Acos(cosTheta);
            return radians * (180 / Math.PI); // 弧度转角度
        }
        // 定义向量结构体
        public struct Vector2D
        {
            public double X;
            public double Y;
            public Vector2D(double x, double y)
            {
                X = x;
                Y = y;
            }
        }
        #region 节点去重
        private static void RemoveDuplicatePointsInRing(IRing ring)
        {
            IPointCollection pointColl = ring as IPointCollection;
            if (pointColl == null || pointColl.PointCount <= 1) return;
            // 步骤1:提取所有点到临时列表
            List allPoints = new List();
            for (int i = 0; i < pointColl.PointCount; i++)
            {
                allPoints.Add(pointColl.get_Point(i));
            }
            // 步骤2:全局去重(支持X/Y/Z/M全维度比较)
            HashSet seenCoordinates = new HashSet();
            List uniquePoints = new List();
            foreach (IPoint point in allPoints)
            {
                // 生成坐标唯一键(根据需求调整是否包含Z/M)
                string coordKey = GetCoordinateKey(point);
                if (!seenCoordinates.Contains(coordKey))
                {
                    seenCoordinates.Add(coordKey);
                    uniquePoints.Add(point);
                }
            }
            // 步骤3:重建点集合(先清空再添加去重点)
            pointColl.RemovePoints(0, pointColl.PointCount); // 清空原始点
            foreach (IPoint uniquePoint in uniquePoints)
            {
                pointColl.AddPoint(uniquePoint);
            }
            // 步骤4:确保环闭合(最后一点与第一点一致)
            ring.Close();
        }
        // 生成坐标唯一键(可根据需求调整比较维度)
        private static string GetCoordinateKey(IPoint point)
        {
            // 仅比较X/Y(忽略Z/M)
            double x = point.X;
            double y = point.Y;
            return $"{x:F6},{y:F6}"; // 保留6位小数避免精度问题
        }
        #endregion
        /// 
        /// 判断图形是否存在狭长
        /// 
        /// 
        /// 
        private static string ISNarrow(IGeometry geometry)
        {
            try
            {
                var strgeometry = GeometryConvertHelper.ConvertIGeoemtryToWKT(geometry);
                NetTopologySuite.Geometries.Geometry ntsGeometry = (NetTopologySuite.Geometries.Geometry)new WKBReader().Read(GeometryConvertHelper.ConvertGeometryToWKB(geometry));
                // 内缩参数(侵蚀)
                var innerBufferParams = new BufferParameters
                {
                    QuadrantSegments = 30,          // 内缩平滑度
                    JoinStyle = JoinStyle.Bevel,    // 斜角连接避免尖锐残留
                    EndCapStyle = EndCapStyle.Square  // 平端帽处理开放线段
                };
                var ntsGeometry1 = ntsGeometry.Buffer(-0.05, innerBufferParams);  // 内缩0.1
                strgeometry = ntsGeometry1.AsText();
                if (strgeometry == "POLYGON EMPTY")
                {
                    return strgeometry;
                }
                // 外扩参数(膨胀)
                var outerBufferParams = new BufferParameters
                {
                    QuadrantSegments = 200,  // 高平滑度外扩
                    JoinStyle = JoinStyle.Mitre,
                    MitreLimit = 2  // 限制尖锐拐角延伸长度
                };
                var ntsGeometry2 = ntsGeometry1.Buffer(0.05, outerBufferParams);  // 外扩0.1
                strgeometry = ntsGeometry2.AsText();
                double length1 = ntsGeometry.Length;
                int pointCount1 = ntsGeometry.NumPoints;
                double length2 = ntsGeometry2.Length;
                int pointCount2 = ntsGeometry2.NumPoints;
                double delta_length = length1 - length2;
                double avg_halfangle = 180 * (pointCount1 - 1 - 2) / (pointCount1 - 1) / 2;
                double conner_normal_length = 2 * 0.05 / Math.Tan(avg_halfangle * (Math.PI / 180));
                if (delta_length > 8 * conner_normal_length * (pointCount1 - 1))
                {
                    return strgeometry;
                }
            }
            catch (Exception ex)
            {
            }
            return string.Empty;
        }
    }
    public class EarClipper
    {
        // 三角剖分结果(每个三角形为3个点的集合)
        public List> Triangles { get; private set; }
        public EarClipper()
        {
            Triangles = new List>();
        }
        // 多边形整体方向(顺时针/逆时针)
        private bool _isCounterClockwise;
        /// 
        /// 对多边形执行耳切法三角剖分
        /// 
        /// 输入多边形(需为简单多边形,无自交)
        /// 三角剖分结果
        public bool Clip(IPolygon polygon)
        {
            if (polygon == null || polygon.IsEmpty)
                return false;
            // 提取多边形外环的顶点(简单多边形默认处理外环)
            IPointCollection pointCollection = polygon as IPointCollection;
            if (pointCollection == null || pointCollection.PointCount < 3)
                return false;
            // 转换为顶点列表(排除最后一个闭合点)
            List vertices = new List();
            for (int i = 0; i < pointCollection.PointCount - 1; i++)
            {
                IPoint p = pointCollection.get_Point(i);
                vertices.Add(p);
            }
            // 关键:计算多边形整体方向(顺时针/逆时针)
            _isCounterClockwise = IsPolygonCounterClockwise(vertices);
            // 执行耳切法
            Triangles.Clear();
            ClipEars(vertices);
            return Triangles.Count > 0;
        }
        /// 
        /// 迭代切割耳
        /// 
        private void ClipEars(List vertices)
        {
            if (vertices.Count < 3) return;
            int index = 0;
            while (vertices.Count > 3)
            {
                // 循环取顶点(处理索引越界)
                int prevIndex = (index - 1 + vertices.Count) % vertices.Count;
                int currIndex = index % vertices.Count;
                int nextIndex = (index + 1) % vertices.Count;
                IPoint prev = vertices[prevIndex];
                IPoint curr = vertices[currIndex];
                IPoint next = vertices[nextIndex];
                // 检查当前三点是否构成"耳"
                if (IsConvex(prev, curr, next) && IsEar(prev, curr, next, vertices))
                {
                    // 记录三角形
                    Triangles.Add(new List { prev, curr, next });
                    // 移除当前顶点(切割耳)
                    vertices.RemoveAt(currIndex);
                    // 重置索引(从下一个顶点开始检查)
                    index = 0;
                }
                else
                {
                    index++;
                    // 防止死循环(理论上简单多边形必然有耳)
                    if (index >= vertices.Count * 2)
                        break;
                }
            }
            // 添加最后一个三角形
            if (vertices.Count == 3)
            {
                Triangles.Add(new List { vertices[0], vertices[1], vertices[2] });
            }
        }
        /// 
        /// 判断顶点curr是否为凸点(通过叉积)
        /// 
        private bool IsConvex(IPoint prev, IPoint curr, IPoint next)
        {
            // 计算向量:prev->curr 和 curr->next
            double v1x = curr.X - prev.X;
            double v1y = curr.Y - prev.Y;
            double v2x = next.X - curr.X;
            double v2y = next.Y - curr.Y;
            // 叉积(z分量):v1 × v2 = v1x*v2y - v1y*v2x
            double cross = v1x * v2y - v1y * v2x;
            // 叉积≥0:逆时针多边形的凸点(根据多边形方向调整符号)
            // 关键:根据多边形整体方向判断凸点
            if (_isCounterClockwise)
            {
                // 逆时针多边形:叉积 >= 0 为凸点
                return cross >= 0;
            }
            else
            {
                // 顺时针多边形:叉积 <= 0 为凸点(与逆时针相反)
                return cross <= 0;
            }
        }
        /// 
        /// 判断多边形顶点是顺时针还是逆时针排列
        /// 
        private bool IsPolygonCounterClockwise(List vertices)
        {
            double sum = 0;
            int n = vertices.Count;
            for (int i = 0; i < n; i++)
            {
                IPoint p = vertices[i];
                IPoint q = vertices[(i + 1) % n]; // 下一个顶点(首尾相连)
                sum += (q.X - p.X) * (q.Y + p.Y);
            }
            // sum > 0 表示逆时针,sum < 0 表示顺时针
            return sum > 0;
        }
        /// 
        /// 判断三点组成的三角形是否为"耳"(内部无其他顶点)
        /// 
        private bool IsEar(IPoint a, IPoint b, IPoint c, List vertices)
        {
            // 检查所有其他顶点是否在三角形abc内部
            foreach (IPoint p in vertices)
            {
                // 跳过a、b、c本身
                if (p.Equals(a) || p.Equals(b) || p.Equals(c))
                    continue;
                // 判断点p是否在三角形abc内部
                if (IsPointInTriangle(p, a, b, c))
                    return false;
            }
            return true;
        }
        /// 
        /// 判断点p是否在三角形abc内部( barycentric坐标法)
        /// 
        private bool IsPointInTriangle(IPoint p, IPoint a, IPoint b, IPoint c)
        {
            double v0x = c.X - a.X;
            double v0y = c.Y - a.Y;
            double v1x = b.X - a.X;
            double v1y = b.Y - a.Y;
            double v2x = p.X - a.X;
            double v2y = p.Y - a.Y;
            // 计算点积
            double dot00 = v0x * v0x + v0y * v0y;
            double dot01 = v0x * v1x + v0y * v1y;
            double dot02 = v0x * v2x + v0y * v2y;
            double dot11 = v1x * v1x + v1y * v1y;
            double dot12 = v1x * v2x + v1y * v2y;
            // 计算 barycentric坐标
            double invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
            double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
            double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
            // 点在三角形内(包括边界)
            return (u >= 0) && (v >= 0) && (u + v <= 1);
        }
    }
}