RevitAPI之利用网格Mesh创建实体面

本文介绍了一种将Revit中的放样(Sweep)几何元素转换为由多个小三角形组成的网格的方法。通过获取几何元素,将其面三角化,并在文档中描绘出这些三角形。此过程涉及到获取实体面、三角面片化及顶点绘制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Revit的网格是多边形网格,每一个三维面都可以由一系列顶点以及对应的一系列三角形组成。

概念已经知道了,那如何用很多小三角形来表示一个体量(放样)的几何空间面。

解决思路是:
首先获取放样Sweep的几何元素,从其中获取实体和构成实体的面;
然后对“面”进行三角面片化后形成对应的网格,遍历网格的所有三角形并收集所有的顶点;
最后把这些顶点在文档中描绘出来。

代码

 
public void DrawMesh(Document doc, Autodesk.Revit.ApplicationServices.Application app)
        {
            Transaction transaction = new Transaction(doc, "Draw Mesh");
            transaction.Start();


            Sweep sweep = doc.GetElement(new ElementId(2311)) as Sweep;
            Options option = GetGeometryOption(app);
            Autodesk.Revit.DB.GeometryElement geomElement = sweep.get_Geometry(option);


            foreach (GeometryObject geomObj in geomElement)
            {
                Solid geomSolid = geomObj as Solid;
                if (null != geomSolid)
                {
                    foreach (Face geomFace in geomSolid.Faces)
                    {
                        // 对面进行三角面片化形成一个网格 
                        Mesh mesh = geomFace.Triangulate();
                        for (int i = 0; i < mesh.NumTriangles; i++)
                        {
                            MeshTriangle triangular = mesh.get_Triangle(i);
                            // 定义  XYZ 列表来存放三角形的顶点 
                            List<XYZ> triangularPoints = new List<XYZ>();
                            for (int n = 0; n < 3; n++)
                            {
                                XYZ point = triangular.get_Vertex(n);
                                triangularPoints.Add(point);
                            }
                            // 调用方法把所有三角形在文档中描绘出来 
                            DrawTriangle(doc, triangularPoints);
                        }
                    }
                }
            }


            transaction.Commit();
        }
        private void DrawTriangle(Document RevitDoc, List<XYZ> triangularPoints)
        {
            if (triangularPoints.Count > 3)
            {
                CurveArray curveArray = new CurveArray();
                curveArray.Append(Line.CreateBound(triangularPoints[0], triangularPoints[1]));
                curveArray.Append(Line.CreateBound(triangularPoints[0], triangularPoints[2]));
                curveArray.Append(Line.CreateBound(triangularPoints[1], triangularPoints[2]));
                Floor floor = RevitDoc.Create.NewFloor(curveArray, false);
            }
        }
        public Options GetGeometryOption(Autodesk.Revit.ApplicationServices.Application app)
        {
            Autodesk.Revit.DB.Options option = app.Create.NewGeometryOptions();
            option.ComputeReferences = true;      //打开计算几何引用 
            option.DetailLevel = ViewDetailLevel.Fine;      //视图详细程度为最好 
            return option;
        }

=========【更多高级应用请关注公众号】========


===================================


       
以下是完整的 Revit 智能标注插件现,包含所有核心类和功能的完整现: ```csharp using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; using Autodesk.Revit.Exceptions; // ======================================== // 核心命令 - IExternalCommand现 // ======================================== [Transaction(TransactionMode.Manual)] public class SmartDimensionCommand : IExternalCommand { private readonly Logger _logger = new Logger(); public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiApp = commandData.Application; UIDocument uiDoc = uiApp.ActiveUIDocument; Document doc = uiDoc.Document; View activeView = uiDoc.ActiveView; // 配置参数 var config = new PluginConfig { MinLineLength = 0.1, AngleTolerance = 0.001745, BaseDimensionOffset = 0.3, LogFilePath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "RevitDimensioningLog.txt"), MaxOffsetMultiplier = 3.0, OffsetIncrement = 0.1, BoundingBoxPadding = 0.2, DimensionGroupSpacing = 0.3, UseAdaptiveOffset = true, UseGrouping = true, GroupByDirection = true, GroupByType = true, UseParallelProcessing = true, CacheGeometryResults = true, SectionViewDepthExtension = 5.0, DimensionAlignment = DimensionAlignment.Above, MinimumDimensionGap = 0.1, MaxThreadCount = Environment.ProcessorCount }; _logger.Initialize(config.LogFilePath); _logger.Log("开始执行智能标注命令"); _logger.Log($"当前视图: {activeView.Name} ({activeView.Id.IntegerValue})", LogLevel.Debug); try { // 验证视图类型 if (!(activeView is ViewPlan || activeView is ViewSection || activeView.ViewType == ViewType.Elevation)) { _logger.Log("错误:仅支持平面、剖面或立面视图", LogLevel.Error); return Result.Failed; } // 获取选中的构件 var selectedElementIds = uiDoc.Selection.GetElementIds(); if (selectedElementIds.Count == 0) { _logger.Log("提示:请先选择需要标注的构件", LogLevel.Info); return Result.Cancelled; } _logger.Log($"选中了 {selectedElementIds.Count}个元素", LogLevel.Info); using (Transaction trans = new Transaction(doc, "智能标注")) { trans.Start(); _logger.Log("事务启动:智能标注"); try { // 批量获取元素 var selectedElements = selectedElementIds .Select(id => doc.GetElement(id)) .Where(e => e != null && e.IsValidObject) .ToList(); // 提取视图投影线 var geometryExtractor = new GeometryExtractor(doc, config, _logger); var curves = geometryExtractor.ExtractCurves(selectedElements.Select(e => e.Id), activeView); _logger.Log($"成功提取 {curves.Count}条曲线"); // 生成标注 var dimensionCreator = new DimensionCreator(doc, activeView, config, _logger); int createdCount = dimensionCreator.CreateDimensions(curves); _logger.Log($"成功创建 {createdCount}个标注"); trans.Commit(); _logger.Log("事务提交成功:智能标注", LogLevel.Info); return Result.Succeeded; } catch (Exception ex) { _logger.Log($"事务执行失败: {ex.Message}", LogLevel.Error); trans.RollBack(); message = ex.Message; return Result.Failed; } } } catch (Exception ex) { _logger.Log($"命令执行失败: {ex.Message}", LogLevel.Error); message = ex.Message; return Result.Failed; } finally { _logger.Flush(); } } } // ======================================== // 配置参数类 // ======================================== public class PluginConfig { public double MinLineLength { get; set; } // 最小线段长度(过滤太短的线段) public double AngleTolerance { get; set; } // 角度容差(弧度) public double BaseDimensionOffset { get; set; } // 基础标注偏移距离 public string LogFilePath { get; set; } // 日志文件路径 public double MaxOffsetMultiplier { get; set; } // 最大偏移倍数 public double OffsetIncrement { get; set; } // 偏移增量 public double BoundingBoxPadding { get; set; } // 边界框填充 public double DimensionGroupSpacing { get; set; } // 标注组间距 public bool UseAdaptiveOffset { get; set; } // 是否使用自适应偏移 public bool UseGrouping { get; set; } // 是否分组标注 public bool GroupByDirection { get; set; } // 按方向分组 public bool GroupByType { get; set; } // 按类型分组 public bool UseParallelProcessing { get; set; } // 是否使用并行处理 public bool CacheGeometryResults { get; set; } // 是否缓存几何结果 public double SectionViewDepthExtension { get; set; } // 剖面视图深度扩展 public DimensionAlignment DimensionAlignment { get; set; } // 标注对齐方式 public double MinimumDimensionGap { get; set; } // 最小标注间隙 public int MaxThreadCount { get; set; } // 最大线程数 } // ======================================== // 日志记录类 // ======================================== public enum LogLevel { Debug, Info, Warning, Error, Critical } public class Logger { private StreamWriter _logWriter; private readonly Queue<string> _logQueue = new Queue<string>(); private bool _isInitialized = false; public void Initialize(string filePath) { try { _logWriter = new StreamWriter(filePath, true) { AutoFlush = false }; _isInitialized = true; Log("日志系统初始化成功", LogLevel.Info); } catch (Exception ex) { _isInitialized = false; // 如果文件日志失败,使用控制台输出 Console.WriteLine($"日志初始化失败: {ex.Message}"); } } public void Log(string message, LogLevel level = LogLevel.Info) { if (!_isInitialized) return; string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{level}] - {message}"; lock (_logQueue) { _logQueue.Enqueue(logEntry); } } public void LogException(string context, Exception ex) { string fullMessage = $"{context}: {ex.Message}\n{ex.StackTrace}"; Log(fullMessage, LogLevel.Error); if (ex.InnerException != null) { Log($"内部异常: {ex.InnerException.Message}", LogLevel.Error); } } public void Flush() { if (!_isInitialized || _logWriter == null) return; try { lock (_logQueue) { while (_logQueue.Count > 0) { _logWriter.WriteLine(_logQueue.Dequeue()); } _logWriter.Flush(); } } catch (Exception ex) { Console.WriteLine($"日志写入失败: {ex.Message}"); } } } // ======================================== // 几何提取器 // ======================================== public class GeometryExtractor { private readonly Document _doc; private readonly PluginConfig _config; private readonly Logger _logger; private readonly Dictionary<string, List<Curve>> _geometryCache = new Dictionary<string, List<Curve>>(); public GeometryExtractor(Document doc, PluginConfig config, Logger logger) { _doc = doc; _config = config; _logger = logger; } public List<Curve> ExtractCurves(IEnumerable<ElementId> elementIds, View view) { string cacheKey = null; if (_config.CacheGeometryResults) { cacheKey = $"Geometry_{view.Id}_{string.Join("_", elementIds.Select(id => id.IntegerValue))}"; if (_geometryCache.TryGetValue(cacheKey, out var cached)) { _logger.Log($"从缓存中获取几何数据: {cacheKey}", LogLevel.Debug); return cached; } } var curves = new List<Curve>(); var options = new Options { View = view, ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine, IncludeNonVisibleObjects = false }; // 针对剖面图特殊处理 if (view is ViewSection sectionView) { options.Transform = GetSectionViewTransform(sectionView); } // 并行提取几何 ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = _config.MaxThreadCount }; if (_config.UseParallelProcessing) { var bag = new System.Collections.Concurrent.ConcurrentBag<Curve>(); Parallel.ForEach(elementIds, parallelOptions, id => { try { var element = _doc.GetElement(id); if (element == null || !element.IsValidObject || !IsElementDimensionable(element)) return; _logger.Log($"处理元素: {element.Name} ({element.Id.IntegerValue})", LogLevel.Debug); GeometryElement geom = element.get_Geometry(options); if (geom != null) { foreach (var c in ExtractCurvesFromGeometry(geom, element)) bag.Add(c); } } catch (Exception ex) { _logger.LogException($"提取元素 {id}几何失败", ex); } }); curves = bag.ToList(); } else { foreach (var id in elementIds) { try { var element = _doc.GetElement(id); if (element == null || !element.IsValidObject || !IsElementDimensionable(element)) continue; _logger.Log($"处理元素: {element.Name} ({element.Id.IntegerValue})", LogLevel.Debug); GeometryElement geom = element.get_Geometry(options); if (geom != null) { curves.AddRange(ExtractCurvesFromGeometry(geom, element)); } } catch (Exception ex) { _logger.LogException($"提取元素 {id}几何失败", ex); } } } // 曲线去重与过滤 var unique = new HashSet<string>(); var result = new List<Curve>(); foreach (var c in curves) { if (!c.IsBound || c.Length < _config.MinLineLength) continue; var key = GetCurveKey(c); if (unique.Add(key)) result.Add(c); } _logger.Log($"过滤后保留 {result.Count}条唯一曲线", LogLevel.Debug); if (_config.CacheGeometryResults && cacheKey != null) _geometryCache[cacheKey] = result; return result; } private Transform GetSectionViewTransform(ViewSection viewSection) { try { if (viewSection != null) { Transform transform = Transform.Identity; transform.Origin = viewSection.Origin; transform.BasisX = viewSection.RightDirection; transform.BasisY = viewSection.UpDirection; transform.BasisZ = viewSection.ViewDirection.Negate(); return transform; } } catch (Exception ex) { _logger.LogException("获取剖面图变换矩阵失败", ex); } return null; } private IEnumerable<Curve> ExtractCurvesFromGeometry(GeometryElement geomElem, Element element) { if (geomElem == null) yield break; foreach (GeometryObject geomObj in geomElem) { if (geomObj == null) continue; switch (geomObj) { case Curve curve: yield return curve; break; case GeometryInstance instance: foreach (var c in ExtractCurvesFromGeometry(instance.GetInstanceGeometry(), element)) yield return c; break; case GeometryElement subElem: foreach (var c in ExtractCurvesFromGeometry(subElem, element)) yield return c; break; case Mesh mesh: foreach (var c in ExtractCurvesFromMesh(mesh, element)) yield return c; break; case Solid solid: foreach (var c in ExtractCurvesFromSolid(solid, element)) yield return c; break; } } } private IEnumerable<Curve> ExtractCurvesFromMesh(Mesh mesh, Element element) { if (mesh == null) yield break; try { for (int i = 0; i < mesh.NumTriangles; i++) { var tri = mesh.get_Triangle(i); for (int j = 0; j < 3; j++) { var p1 = tri.get_Vertex(j); var p2 = tri.get_Vertex((j + 1) % 3); yield return Line.CreateBound(p1, p2); } } } catch (Exception ex) { _logger.LogException($"提取网格曲线失败 - 元素: {element?.Id}", ex); } } private IEnumerable<Curve> ExtractCurvesFromSolid(Solid solid, Element element) { if (solid == null || solid.Volume <= 0) yield break; try { foreach (Edge edge in solid.Edges) { if (edge != null && edge.AsCurve() is Curve curve) yield return curve; } } catch (Exception ex) { _logger.LogException($"提取体曲线失败 - 元素: {element?.Id}", ex); } } private bool IsElementDimensionable(Element element) { return !(element is View || element is Dimension || element is TextNote || element is AnnotationSymbol || element is RevisionCloud || element is Group || element.IsHidden(element.Document.ActiveView)); } private string GetCurveKey(Curve curve) { if (curve is Line line) { var p1 = line.GetEndPoint(0); var p2 = line.GetEndPoint(1); return $"Line_{Math.Round(Math.Min(p1.X, p2.X), 6)}_" + $"{Math.Round(Math.Min(p1.Y, p2.Y), 6)}_" + $"{Math.Round(Math.Min(p1.Z, p2.Z), 6)}_" + $"{Math.Round(Math.Max(p1.X, p2.X), 6)}_" + $"{Math.Round(Math.Max(p1.Y, p2.Y), 6)}_" + $"{Math.Round(Math.Max(p1.Z, p2.Z), 6)}"; } if (curve is Arc arc) { var p1 = arc.GetEndPoint(0); var p2 = arc.GetEndPoint(1); var center = arc.Center; return $"Arc_{Math.Round(p1.X, 6)}_" + $"{Math.Round(p1.Y, 6)}_" + $"{Math.Round(p1.Z, 6)}_" + $"{Math.Round(p2.X, 6)}_" + $"{Math.Round(p2.Y, 6)}_" + $"{Math.Round(p2.Z, 6)}_" + $"{Math.Round(center.X, 6)}_" + $"{Math.Round(center.Y, 6)}_" + $"{Math.Round(center.Z, 6)}"; } if (curve is Ellipse ellipse) { var center = ellipse.Center; return $"Ellipse_{Math.Round(center.X, 6)}_" + $"{Math.Round(center.Y, 6)}_" + $"{Math.Round(center.Z, 6)}_" + $"{Math.Round(ellipse.RadiusX, 6)}_" + $"{Math.Round(ellipse.RadiusY, 6)}"; } return $"{curve.GetType().Name}_{Math.Round(curve.Length, 6)}"; } } // ======================================== // 标注生成器 // ======================================== public class DimensionCreator { private readonly Document _doc; private readonly View _view; private readonly PluginConfig _config; private readonly Logger _logger; private readonly Dictionary<string, Curve> _processedCurves = new Dictionary<string, Curve>(); private readonly Dictionary<string, BoundingBoxXYZ> _existingDimensionBoxes = new Dictionary<string, BoundingBoxXYZ>(); private const double Tolerance = 0.0001; private const double MaxDimensionLength = 100; // 最大标注长度(米) public DimensionCreator(Document doc, View view, PluginConfig config, Logger logger) { _doc = doc; _view = view; _config = config; _logger = logger; if (config.UseAdaptiveOffset) { _logger.Log("正在加载现有标注信息...", LogLevel.Debug); LoadExistingDimensions(); } } private void LoadExistingDimensions() { try { var dimensionFilter = new ElementClassFilter(typeof(Dimension)); var collector = new FilteredElementCollector(_doc, _view.Id).WherePasses(dimensionFilter); foreach (Dimension dimension in collector.Cast<Dimension>()) { try { BoundingBoxXYZ box = dimension.get_BoundingBox(_view); if (box != null) { string key = $"DimBox_{dimension.Id.IntegerValue}"; _existingDimensionBoxes[key] = box; } } catch (Exception ex) { _logger.LogException($"获取标注边界框失败: {dimension.Id}", ex); } } _logger.Log($"已加载 {_existingDimensionBoxes.Count}个现有标注边界框", LogLevel.Debug); } catch (Exception ex) { _logger.LogException("加载现有标注失败", ex); } } public int CreateDimensions(List<Curve> curves) { int count = 0; _logger.Log($"开始为 {curves.Count}条曲线创建标注", LogLevel.Info); // 分组优化:按方向和类型分组,减少重叠 var grouped = GroupCurves(curves); _logger.Log($"曲线已分组: {grouped.Count}个方向/类型组", LogLevel.Debug); // 创建视图坐标投影面 Plane viewPlane = GetViewProjectionPlane(); if (viewPlane == null) { _logger.Log("无法创建视图投影平面,标注创建中止", LogLevel.Error); return 0; } // 并行创建标注(提升性能,避免UI阻塞) Parallel.ForEach(grouped.Values, group => { _logger.Log($"处理包含 {group.Count}条曲线的组", LogLevel.Debug); foreach (var curve in group) { try { string key = GetCurveKey(curve); lock (_processedCurves) { if (_processedCurves.ContainsKey(key)) { _logger.Log($"跳过已处理曲线: {key.Substring(0,20)}...", LogLevel.Debug); continue; } _processedCurves[key] = curve; } bool created = false; double offset = _config.BaseDimensionOffset; // 计算最优偏移位置 if (_config.UseAdaptiveOffset) { offset = CalculateOptimalOffset(curve, ref offset); } // 根据曲线类型创建标注 if (curve is Line line) { created = CreateLinearDimension(line, viewPlane, offset); } else if (curve is Arc arc) { created = CreateArcDimension(arc, viewPlane, offset); } else if (curve is Ellipse ellipse) { created = CreateEllipseDimensions(ellipse, viewPlane, offset) > 0; } else { created = CreateGenericCurveDimension(curve, viewPlane, offset) > 0; } if (created) { System.Threading.Interlocked.Increment(ref count); _logger.Log($"成功创建标注 #{count}", LogLevel.Debug); } } catch (Autodesk.Revit.Exceptions.InvalidOperationException opEx) { _logger.LogException($"操作不被允许: {opEx.Message}", opEx); } catch (Exception ex) { _logger.LogException($"创建标注失败 - 曲线类型: {curve.GetType().Name}", ex); } } }); return count; } /// <summary> /// 将曲线按方向和类型分组 /// </summary> private Dictionary<string, List<Curve>> GroupCurves(List<Curve> curves) { var groups = new Dictionary<string, List<Curve>>(); foreach (var curve in curves) { string groupKey = ""; // 按方向分组 if (_config.GroupByDirection) { var direction = GetCurveDirection(curve); groupKey += $"Dir_{direction.X:F4}_{direction.Y:F4}_{direction.Z:F4}_"; } // 按类型分组 if (_config.GroupByType) { groupKey += $"{curve.GetType().Name}"; } else { groupKey += "Curve"; } if (!groups.ContainsKey(groupKey)) { groups[groupKey] = new List<Curve>(); } groups[groupKey].Add(curve); } return groups; } /// <summary> /// 获取曲线的方向向量 /// </summary> private XYZ GetCurveDirection(Curve curve) { if (curve is Line line) { return (line.GetEndPoint(1) - line.GetEndPoint(0)).Normalize(); } if (curve is Arc arc) { return arc.Center - arc.GetEndPoint(0); } if (curve is Ellipse ellipse) { return ellipse.Center - ellipse.GetEndPoint(0); } // 对于通用曲线,取起点切线方向 return curve.ComputeDerivatives(0, true).BasisX; } /// <summary> /// 创建线性标注 /// </summary> private bool CreateLinearDimension(Line line, Plane plane, double offset) { try { // 获取参考元素 var references = GetReferencesForCurve(line); if (references.Count < 2) return false; // 计算偏移向量 XYZ direction = (references[1].GlobalPoint - references[0].GlobalPoint).Normalize(); XYZ normal = plane.Normal; XYZ offsetVector = direction.CrossProduct(normal).Normalize().Multiply(offset); // 创建定位线 XYZ dimOrigin = references[0].GlobalPoint.Add(offsetVector); Line dimensionLine = Line.CreateUnbound(dimOrigin, direction); // 创建标注 Dimension dimension = _doc.Create.NewDimension( _view, dimensionLine, references.Cast<Reference>().ToList()); return true; } catch (Exception ex) { _logger.LogException($"创建线性标注失败: {ex.Message}", ex); return false; } } /// <summary> /// 创建弧形标注 /// </summary> private bool CreateArcDimension(Arc arc, Plane plane, double offset) { try { XYZ center = arc.Center; double radius = arc.Radius; // 创建半径标注 Reference centerRef = ReferenceFactory.CreateCenterPointReference(_doc, center); Reference arcRef = ReferenceFactory.CreateCurveReference(_doc, arc); // 计算偏移点 XYZ viewDirection = _view.ViewDirection; XYZ radiusDir = (arc.GetEndPoint(0) - center).Normalize(); XYZ offsetDir = radiusDir.CrossProduct(viewDirection).Normalize(); XYZ leaderPoint = center.Add(offsetDir.Multiply(radius + offset)); // 创建半径标注 _doc.Create.NewRadiusDimension(_view, arcRef, leaderPoint); // 创建弧长标注 LocationCurve arcLocation = arc.Clone() as LocationCurve; var arcReferences = new[] { ReferenceFactory.CreateCurveReference(_doc, arcLocation.Curve, 0), ReferenceFactory.CreateCurveReference(_doc, arcLocation.Curve, 1), ReferenceFactory.CreateCurveReference(_doc, arcLocation.Curve, 0.5) }; _doc.Create.NewArcLengthDimension(_view, ReferenceFactory.CreateCurveReference(_doc, arc), leaderPoint.Add(offsetDir.Multiply(offset))); return true; } catch (Exception ex) { _logger.LogException($"创建弧形标注失败: {ex.Message}", ex); return false; } } /// <summary> /// 创建椭圆标注 /// </summary> private int CreateEllipseDimensions(Ellipse ellipse, Plane plane, double offset) { int count = 0; try { XYZ center = ellipse.Center; // 创建主半轴标注 Reference centerRef = ReferenceFactory.CreateCenterPointReference(_doc, center); Reference majorAxisRef = ReferenceFactory.CreateLineReference(_doc, Line.CreateBound(center, ellipse.XDirection.Multiply(ellipse.RadiusX))); Dimension majorDim = _doc.Create.NewAlignmentDimension(_view, new DimensionSegment(centerRef, ReferenceFactory.CreatePointReference(_doc, ellipse.Evaluate(0, true)), new DimensionSegment(centerRef, ReferenceFactory.CreatePointReference(_doc, ellipse.Evaluate(0.5, true)))); count++; // 创建次半轴标注 Reference minorAxisRef = ReferenceFactory.CreateLineReference(_doc, Line.CreateBound(center, ellipse.YDirection.Multiply(ellipse.RadiusY))); Dimension minorDim = _doc.Create.NewAlignmentDimension(_view, new DimensionSegment(centerRef, ReferenceFactory.CreatePointReference(_doc, ellipse.Evaluate(0.25, true)), new DimensionSegment(centerRef, ReferenceFactory.CreatePointReference(_doc, ellipse.Evaluate(0.75, true)))); count++; return count; } catch (Exception ex) { _logger.LogException($"创建椭圆标注失败: {ex.Message}", ex); return count; } } /// <summary> /// 创建通用曲线标注 /// </summary> private int CreateGenericCurveDimension(Curve curve, Plane plane, double offset) { int count = 0; try { // 在曲线上取多个点 List<double> paramPoints = new List<double> { 0, 0.25, 0.5, 0.75, 1 }; // 创建定位线 XYZ start = curve.GetEndPoint(0); XYZ end = curve.GetEndPoint(1); XYZ direction = (end - start).Normalize(); XYZ offsetVector = direction.CrossProduct(plane.Normal).Normalize().Multiply(offset); // 创建点参考列表 List<ReferencePoint> refPoints = new List<ReferencePoint>(); foreach (double p in paramPoints) { XYZ point = curve.Evaluate(p, true); refPoints.Add(new ReferencePoint(point + offsetVector, ReferenceFactory.CreatePointReference(_doc, point))); } // 创建标注 Dimension dimension = _doc.Create.NewMultiSegmentDimension( _view, plane, new DimensionSegment[] { }, refPoints); count = refPoints.Count - 1; return count; } catch (Exception ex) { _logger.LogException($"创建通用曲线标注失败: {ex.Message}", ex); return 0; } } /// <summary> /// 为曲线生成参考元素 /// </summary> private List<Reference> GetReferencesForCurve(Curve curve) { var references = new List<Reference>(); // 创建端点参考 references.Add(ReferenceFactory.CreatePointReference(_doc, curve.GetEndPoint(0))); references.Add(ReferenceFactory.CreatePointReference(_doc, curve.GetEndPoint(1))); // 为长线段创建中点参考 if (curve.Length > 5) { references.Add(ReferenceFactory.CreatePointReference( _doc, curve.Evaluate(0.5, true))); } return references; } /// <summary> /// 计算最优标注位置 /// </summary> private double CalculateOptimalOffset(Curve curve, double baseOffset) { int attempt = 0; int maxAttempts = (int)(_config.MaxOffsetMultiplier * (1 / _config.OffsetIncrement)); double offset = baseOffset; double increment = _config.OffsetIncrement; while (attempt < maxAttempts) { _logger.Log($"尝试偏移位置 #{attempt}: {offset}", LogLevel.Debug); // 检查偏移位置是否可用 if (!CheckPositionConflict(curve, offset)) { _logger.Log($"找到合适位置: 偏移={offset}", LogLevel.Debug); return offset; } // 调整偏移方向(尝试另一侧) if (attempt % 2 == 0) offset = baseOffset + (increment * (attempt + 1) / 2); else offset = baseOffset - (increment * (attempt + 1) / 2); attempt++; } _logger.Log($"未找到无冲突位置,使用默认位置: {baseOffset}", LogLevel.Warning); return baseOffset; } /// <summary> /// 检查标注位置是否存在冲突 /// </summary> private bool CheckPositionConflict(Curve curve, double offset) { try { // 计算标注位置边界框 BoundingBoxXYZ dimBox = EstimateDimensionBoundingBox(curve, offset); // 扩大边界框以包含安全间距 XYZ min = dimBox.Min.Subtract(new XYZ( _config.MinimumDimensionGap, _config.MinimumDimensionGap, _config.MinimumDimensionGap)); XYZ max = dimBox.Max.Add(new XYZ( _config.MinimumDimensionGap, _config.MinimumDimensionGap, _config.MinimumDimensionGap)); dimBox.Min = min; dimBox.Max = max; // 检查与现有元素的冲突 Outline outline = new Outline(min, max); BoundingBoxIntersectsFilter bboxFilter = new BoundingBoxIntersectsFilter(outline); FilteredElementCollector collector = new FilteredElementCollector(_doc, _view.Id) .WherePasses(bboxFilter) .WhereElementIsNotElementType() .WhereElementIsViewIndependent(); // 检查与现有标注的冲突 foreach (var existingBox in _existingDimensionBoxes.Values) { if (existingBox.Min.Z != dimBox.Min.Z) continue; if (existingBox.Min.X < dimBox.Max.X && existingBox.Max.X > dimBox.Min.X && existingBox.Min.Y < dimBox.Max.Y && existingBox.Max.Y > dimBox.Min.Y) { return true; } } return collector.Any(); } catch (Exception ex) { _logger.LogException($"检查标注位置冲突失败: {ex.Message}", ex); return false; } } /// <summary> /// 估计标注的边界框 /// </summary> private BoundingBoxXYZ EstimateDimensionBoundingBox(Curve curve, double offset) { if (curve is Line line) { XYZ start = line.GetEndPoint(0); XYZ end = line.GetEndPoint(1); XYZ midPoint = (start + end) / 2; XYZ dimensionPosition = midPoint + line.Direction.CrossProduct(XYZ.BasisZ).Normalize() * offset; return new BoundingBoxXYZ { Min = dimensionPosition - new XYZ(curve.Length / 2, 0.1, 0.01), Max = dimensionPosition + new XYZ(curve.Length / 2, 0.1, 0.01) }; } else if (curve is Arc arc) { XYZ center = arc.Center; double radius = arc.Radius; return new BoundingBoxXYZ { Min = center - new XYZ(radius + offset, radius + offset, 0.01), Max = center + new XYZ(radius + offset, radius + offset, 0.01) }; } // 通用曲线边界框 return new BoundingBoxXYZ { Min = curve.GetBoundingBox().Min - new XYZ(offset, offset, 0.01), Max = curve.GetBoundingBox().Max + new XYZ(offset, offset, 0.01) }; } /// <summary> /// 获取曲线唯一标识键 /// </summary> private string GetCurveKey(Curve curve) { if (curve is Line line) { var p1 = line.GetEndPoint(0); var p2 = line.GetEndPoint(1); return $"Line_{Math.Round(p1.X, 6)}_{Math.Round(p1.Y, 6)}_" + $"{Math.Round(p2.X, 6)}_{Math.Round(p2.Y, 6)}"; } if (curve is Arc arc) { return $"Arc_{Math.Round(arc.Center.X, 6)}_{Math.Round(arc.Center.Y, 6)}_{Math.Round(arc.Radius, 6)}"; } return curve.GetType().Name; } } // ======================================== // 参考对象工厂 // ======================================== public static class ReferenceFactory { public static Reference CreatePointReference(Document doc, XYZ point) { // 创建临时几何点 PointElement pointElement = PointElement.Create(doc, point); return new Reference(pointElement); } public static Reference CreateCurveReference(Document doc, Curve curve) { // 创建临时模型线 Plane plane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, curve.GetEndPoint(0)); SketchPlane sketch = SketchPlane.Create(doc, plane); ModelCurve modelCurve = doc.FamilyCreate.NewModelCurve(curve, sketch); return new Reference(modelCurve); } public static Reference CreateLineReference(Document doc, Line line) { // 创建临时模型线 Plane plane = Plane.CreateByNormalAndOrigin(line.Direction.CrossProduct(XYZ.BasisZ), line.GetEndPoint(0)); SketchPlane sketch = SketchPlane.Create(doc, plane); ModelCurve modelCurve = doc.FamilyCreate.NewModelCurve(line, sketch); return new Reference(modelCurve); } public static Reference CreateCenterPointReference(Document doc, XYZ center) { // 创建临时几何点 PointElement point = PointElement.Create(doc, center); return new Reference(point); } } // ======================================== // 标注对齐方式枚举 // ======================================== public enum DimensionAlignment { Above, Below, Left, Right }你自己检查检查
06-12
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值