diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs" "b/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs"
index 6bd4b8236c7a82fea55c74f6764f8ecbbd728afa..34e5824a2438061b578d4a858a71b5b8c51b41a6 100644
--- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs"
+++ "b/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs"
@@ -1,7 +1,5 @@
-namespace IFoxCAD.Cad;
-///
-/// 充填扩展类
-///
+namespace IFoxCAD.Cad;
+
public static class HatchEx
{
///
@@ -14,4 +12,303 @@ public static void ForEach(this Hatch hatch, Action action)
for (int i = 0; i < hatch.NumberOfLoops; i++)
action.Invoke(hatch.GetLoopAt(i));
}
+
+ ///
+ /// 提取已存在的关联边界(一个边界环里所有的对象 id 组成一个 ObjectIdCollection)
+ ///
+ ///
+ ///
+ ///
+ public static List? GetAssociatedBoundaryIds(this Hatch hatch)
+ {
+ if (!hatch.Id.IsOk())
+ throw new ArgumentException("填充未加入或不存在于数据库");
+
+ if (!hatch.Associative)
+ return null;
+
+ var listObjIdColl = new List();
+
+ for (var i = 0; i < hatch.NumberOfLoops; i++)
+ {
+ var assIds = hatch.GetAssociatedObjectIdsAt(i);
+ if (assIds != null)
+ {
+ var objIds = new ObjectIdCollection();
+ foreach (ObjectId id in assIds)
+ {
+ if (id.IsOk())
+ objIds.Add(id);
+ }
+
+ if (objIds.Count == 0)
+ {
+ throw new ArgumentException("关联的填充边界被删除后没有清理反应器,请调用:" +
+ "\n hatch.RemoveAssociatedObjectIds()" +
+ "\n hatch.Associative = false");
+ }
+
+ listObjIdColl.Add(objIds);
+ }
+ }
+
+ return listObjIdColl;
+ }
+
+ ///
+ /// 创建边界(仅创建于内存中,未加入数据库)
+ ///
+ ///
+ /// 关联边界
+ /// 边界环列表(一个边界环里所有的对象组成一个 DBObjectCollection)
+ public static List CreateBoundarys(this Hatch hatch)
+ {
+ if (!hatch.Id.IsOk())
+ throw new ArgumentException("填充未加入或不存在于数据库");
+
+ var listDbObjColl = new List();
+
+ for (int i = 0; i < hatch.NumberOfLoops; i++)
+ {
+ var objColl = new DBObjectCollection();
+ var loop = hatch.GetLoopAt(i);
+ bool isCurve2d = true;
+
+ if (loop.IsPolyline)
+ {
+ // 判断为圆形:
+ // 上下两个圆弧,然后填充,就会生成此种填充
+ // 顶点数是3,凸度是半圆,两个半圆就是一个圆形
+ if (loop.Polyline.Count == 3 && loop.Polyline[0].Bulge == 1 && loop.Polyline[1].Bulge == 1 ||
+ loop.Polyline.Count == 3 && loop.Polyline[0].Bulge == -1 && loop.Polyline[1].Bulge == -1)
+ {
+ var center = PointEx.GetMidPointTo(loop.Polyline[0].Vertex, loop.Polyline[1].Vertex);
+ var radius = loop.Polyline[0].Vertex.GetDistanceTo(loop.Polyline[1].Vertex) * 0.5;
+ var circle = new Circle(center.Point3d(), Vector3d.ZAxis, radius);
+ objColl.Add(circle);
+ }
+ else
+ {
+ // 遍历多段线信息
+ var bvc = loop.Polyline;
+ var pl = new Polyline();
+ pl.SetDatabaseDefaults();
+ for (int j = 0; j < bvc.Count; j++)
+ {
+ var bvw = new BulgeVertexWidth(bvc[j]);
+ pl.AddVertexAt(j, bvw.Vertex, bvw.Bulge, bvw.StartWidth, bvw.EndWidth);
+ }
+ objColl.Add(pl);
+ }
+
+ isCurve2d = false;
+ }
+ else if (loop.Curves.Count == 2) // 1是不可能的,大于2的是曲线; 边界是曲线,过滤可能是圆形的情况
+ {
+ if (loop.Curves.Count != 2) {
+ throw new ArgumentException(
+ "边界非多段线,而且点数!=2,点数为:" + nameof(loop.Curves.Count) + ";两个矩形交集的时候会出现此情况.");
+ }
+
+ // 判断为圆形:
+ // 用一条(不是两条)多段线画出两条圆弧为正圆,就会生成此种填充
+ // 边界为曲线,数量为2,可能是两个半圆曲线,如果是,就加入圆形数据中
+
+ // 第一段
+ var getCurves1Pts = loop.Curves[0].GetSamplePoints(3); // 曲线取样点分两份(3点)
+ var mid1Pt = getCurves1Pts[1]; // 腰点
+ double bulge1 = loop.Curves[0].StartPoint.GetArcBulge(mid1Pt, loop.Curves[0].EndPoint);
+
+ // 第二段
+ var getCurves2Pts = loop.Curves[1].GetSamplePoints(3);
+ var mid2Pt = getCurves2Pts[1];
+ double bulge2 = loop.Curves[1].StartPoint.GetArcBulge(mid2Pt, loop.Curves[1].EndPoint);
+
+ // 第一段上弧&&第二段反弧 || 第一段反弧&&第二段上弧
+ if (bulge1 == -1 && bulge2 == -1 || bulge1 == 1 && bulge2 == 1)
+ {
+ var center = PointEx.GetMidPointTo(loop.Curves[0].StartPoint, loop.Curves[1].StartPoint);
+ var radius = loop.Curves[0].StartPoint.GetDistanceTo(loop.Curves[1].StartPoint) * 0.5;
+ var circle = new Circle(center.Point3d(), Vector3d.ZAxis, radius);
+ objColl.Add(circle);
+ isCurve2d = false;
+ }
+ }
+
+ // 边界是曲线
+ if (isCurve2d)
+ {
+ int pLineCount = 0; //记录多段线数量
+ int curveIsClosed = 0; // 取每一段曲线,曲线可能是直线来的,但是圆弧会按照顶点来分段
+ bool newPline = true; // 是否开始新的多段线(一个边界中可能有多条多段线)
+ bool firstIsPline = false; //遍历边界的第一个子段为多段线(遍历时不一定从多段线的首段开始)
+ List? polyLineVertexs = null;
+ List> polyLineData = new();
+
+ // 遍历边界的多个子段
+ foreach (Curve2d curve in loop.Curves)
+ {
+ // 计数用于实现闭合
+ curveIsClosed++;
+
+ if (curve is CircularArc2d or LineSegment2d)
+ {
+ var pts = curve.GetSamplePoints(3);
+ var midPt = pts[1];
+
+ // 判断为多段线圆:
+ // 首尾相同,就是圆形
+ if (curve.StartPoint.IsEqualTo(curve.EndPoint, new Tolerance(1e-6, 1e-6)))
+ {
+ // 获取起点,然后采样三点,中间就是对称点(直径点)
+ var center = PointEx.GetMidPointTo(curve.StartPoint, midPt);
+ var radius = curve.StartPoint.GetDistanceTo(midPt) * 0.5;
+ var circle = new Circle(center.Point3d(), Vector3d.ZAxis, radius);
+ objColl.Add(circle);
+ // 添加在中部的多段线末尾点
+ if (curveIsClosed > 1 && !newPline)
+ polyLineVertexs?.Add(new BulgeVertexWidth(curve.StartPoint, 0));
+ // 开始新的多段线
+ newPline = true;
+ continue;
+ }
+
+ if (curveIsClosed == 1)
+ firstIsPline = true;
+
+ if (newPline)
+ {
+ polyLineVertexs = new();
+ polyLineData.Add(polyLineVertexs);
+ newPline = false;
+ pLineCount++;
+ }
+
+ // 判断为多段线,圆弧或直线:
+ double bulge = curve.StartPoint.GetArcBulge(midPt, curve.EndPoint);
+ polyLineVertexs?.Add(new BulgeVertexWidth(curve.StartPoint, bulge));
+
+ // 末尾点,不闭合的情况下就要获取这个
+ if (curveIsClosed == loop.Curves.Count)
+ {
+ if (firstIsPline && pLineCount > 1)
+ {
+ // 连接首尾多段线
+ polyLineData[0].ForEach(bvw => polyLineData[^1].Add(bvw));
+ polyLineData.RemoveAt(0);
+ }
+ else
+ polyLineVertexs?.Add(new BulgeVertexWidth(curve.EndPoint, 0));
+ }
+
+ continue;
+ }
+
+ // 判断为样条曲线:
+ if (curve is NurbCurve2d spl)
+ objColl.Add(spl.ToCurve());
+
+ // 判断为椭圆:
+ if (curve is EllipticalArc2d eArc2d)
+ {
+ var startParam = eArc2d.IsClockWise ? -eArc2d.EndAngle : eArc2d.StartAngle;
+ var endParam = eArc2d.IsClockWise ? -eArc2d.StartAngle : eArc2d.EndAngle;
+ var ellipse = new Ellipse(
+ eArc2d.Center.Point3d(),
+ Vector3d.ZAxis,
+ eArc2d.MajorAxis.Convert3d() * eArc2d.MajorRadius,
+ eArc2d.MinorRadius / eArc2d.MajorRadius,
+ Math.Atan2(Math.Sin(startParam) * eArc2d.MinorRadius,
+ Math.Cos(startParam) * eArc2d.MajorRadius),
+ Math.Atan2(Math.Sin(endParam) * eArc2d.MinorRadius,
+ Math.Cos(endParam) * eArc2d.MajorRadius));
+ objColl.Add(ellipse);
+ }
+
+ // 添加在中部的多段线末尾点
+ if (curveIsClosed > 1 && !newPline)
+ polyLineVertexs?.Add(new BulgeVertexWidth(curve.StartPoint, 0));
+ // 开始新的多段线
+ newPline = true;
+ }
+
+ // 生成多段线
+ polyLineData.ForEach(bvws =>
+ {
+ if (bvws.Count == 0) return;
+ var pl = new Polyline();
+ pl.SetDatabaseDefaults();
+ for (int j = 0; j < bvws.Count; j++)
+ pl.AddVertexAt(j, bvws[j].Vertex, bvws[j].Bulge, bvws[j].StartWidth, bvws[j].EndWidth);
+ objColl.Add(pl);
+ });
+ }
+
+ listDbObjColl.Add(objColl);
+ };
+
+ return listDbObjColl;
+ }
+
+ ///
+ /// 对已存在于数据库的填充重新设置边界并计算
+ ///
+ ///
+ /// 边界对象(一个边界环里所有的对象 id 组成一个 ObjectIdCollection)
+ ///
边界必需是封闭的环, 可以是一条线围合而成也可以是多条线首尾相连围合而成
+ ///
多个外边界的时候, 建议顺序为(外边界,外边界,外边界,普通边界....), 或(外边界, 普通边界.....外边界, 普通边界....)
+ ///
+ /// 关联边界(默认保持原样)
+ public static void ResetBoundarys(this Hatch hatch,
+ List boundaryIds, bool? associative = null)
+ {
+ if (!hatch.Id.IsOk())
+ throw new ArgumentException("填充未加入或不存在于数据库");
+
+ boundaryIds.ForEach(ids =>
+ {
+ foreach (ObjectId id in ids)
+ {
+ if (!id.IsOk())
+ throw new ArgumentException("边界未加入或不存在于数据库");
+ }
+ });
+
+ using (hatch.ForWrite())
+ {
+ while (hatch.NumberOfLoops > 0)
+ hatch.RemoveLoopAt(0);
+
+ if (associative != null)
+ hatch.Associative = associative == true;
+
+ var isOutermost = true;
+
+ boundaryIds.ForEach(ids =>
+ {
+ try
+ {
+ // 要先添加最外面的边界
+ if (isOutermost)
+ {
+ isOutermost = false;
+ hatch.AppendLoop(HatchLoopTypes.Outermost, ids);
+ }
+ else
+ {
+ // HatchLoopTypes.External 似乎比 HatchLoopTypes.Default 更不容易出问题
+ hatch.AppendLoop(HatchLoopTypes.External, ids);
+ }
+ }
+ catch (Exception ex)
+ {
+ Env.Editor.WriteMessage(Environment.NewLine
+ + "发生错误,传入的边界不符合要求,请核实传入的边界是否为封闭的");
+ throw new Exception(ex.Message);
+ }
+ });
+
+ hatch.EvaluateHatch(true);
+ }
+ }
}
\ No newline at end of file