diff --git a/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs b/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs index cffdca2d5ff798629dfdb67f3f12150fe6b64f2a..d21d81851a17cacd5de05a4987a4e8f995937525 100644 --- a/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs +++ b/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs @@ -449,40 +449,51 @@ public static OrientationType IsClockWise(this IEnumerable pnts) return ca2d; } + /// + /// 叉积,二维叉乘计算 + /// + /// 原点 + /// oa向量 + /// ob向量,此为判断点 + /// 返回值有正负,表示绕原点四象限的位置变换,也就是有向面积 + private static double Cross(Point2d o, Point2d a, Point2d b) + { + return (a.X - o.X) * (b.Y - o.Y) - (a.Y - o.Y) * (b.X - o.X); + } + /// /// 获取点集的凸包 /// /// 点集 /// 凸包 - public static List ConvexHull(this List points) + public static List? ConvexHull(this List points) { - if (points.Count <= 1) - return points; + if (points.Count < 3) return null; - int n = points.Count, k = 0; - List H = [..new Point2d[2 * n]]; + //坐标排序 + points = points.OrderBy(p => p.X).ThenBy(p => p.Y).ToList(); - points.Sort((a, b) => a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X)); + var hullPts = new List(); - // Build lower hull - for (var i = 0; i < n; ++i) - { - while (k >= 2 && IsClockWise(H[k - 2], H[k - 1], points[i]) == - OrientationType.CounterClockWise) - k--; - H[k++] = points[i]; + //构建下凸包 + foreach (var pt in points) { + while (hullPts.Count >= 2 && Cross(hullPts[^2], hullPts[^1], pt) <= 0) + hullPts.RemoveAt(hullPts.Count - 1); + hullPts.Add(pt); } - // Build upper hull - for (int i = n - 2, t = k + 1; i >= 0; i--) - { - while (k >= t && IsClockWise(H[k - 2], H[k - 1], points[i]) == - OrientationType.CounterClockWise) - k--; - H[k++] = points[i]; + //构建上凸包 + var lowerHullCount = hullPts.Count + 1; + for (var i = points.Count - 2; i >= 0; i--) { + while (hullPts.Count >= lowerHullCount && Cross(hullPts[^2], hullPts[^1], points[i]) <= 0) + hullPts.RemoveAt(hullPts.Count - 1); + hullPts.Add(points[i]); } - return H.Take(k - 1).ToList(); + //移除与起点重复的尾点 + hullPts.RemoveAt(hullPts.Count - 1); + + return hullPts.Count >= 3 ? hullPts : null; } #endregion PointList