From eb694fdf4f13815d191ebda938b8664b5a094cc5 Mon Sep 17 00:00:00 2001 From: yupeng_dyp Date: Sun, 2 Feb 2025 11:58:43 +0000 Subject: [PATCH] =?UTF-8?q?update=20src/CAD/IFox.CAD.Shared/ExtensionMetho?= =?UTF-8?q?d/GeometryEx.cs.=20=E4=BF=AE=E5=A4=8D=E5=8E=9F=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E4=BC=9A=E5=87=BA=E7=8E=B0=E5=85=B1=E7=BA=BF=E7=82=B9?= =?UTF-8?q?=E5=8F=8A=E4=BC=A0=E5=85=A5=E7=9A=84=E7=82=B9=E9=9B=86=E5=A6=82?= =?UTF-8?q?=E6=9E=9C=E6=9C=89=E9=87=8D=E7=82=B9=E6=97=B6=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E5=87=B8=E5=8C=85=E5=8F=AF=E8=83=BD=E4=BC=9A=E6=9C=89?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=88=E5=85=B6?= =?UTF-8?q?=E5=AE=9E=E7=AE=97=E6=B3=95=E4=B8=8E=E5=8E=9F=E6=9D=A5=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E6=A0=B7=EF=BC=8C=E6=B2=A1=E6=9C=89=E5=8E=BB=E6=B7=B1?= =?UTF-8?q?=E7=A9=B6=E5=8E=9F=E5=87=BD=E6=95=B0=E4=BC=9A=E6=9C=89=E5=89=8D?= =?UTF-8?q?=E9=9D=A2=E7=9A=84=E9=97=AE=E9=A2=98=E7=9A=84=E5=85=B7=E4=BD=93?= =?UTF-8?q?=E5=8E=9F=E5=9B=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yupeng_dyp --- .../ExtensionMethod/GeometryEx.cs | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs index d5e213e..02af063 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs +++ b/src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs @@ -401,6 +401,18 @@ 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); + } + /// /// 获取点集的凸包 /// @@ -408,34 +420,32 @@ public static OrientationType IsClockWise(this IEnumerable pnts) /// 凸包 public static List? ConvexHull(this List points) { - if (points is null) - return null; + if (points.Count < 3) return null; - if (points.Count <= 1) - return points; + //坐标排序 + points = points.OrderBy(p => p.X).ThenBy(p => p.Y).ToList(); - int n = points.Count, k = 0; - List H = new(new Point2d[2 * n]); + var hullPts = new List(); - points.Sort((a, b) => - a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X)); - - // Build lower hull - for (int 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; } -- Gitee