RevitAPI: 如何在详图构件上创建尺寸标注

本文介绍了一种在Revit中对详图构件进行尺寸标注的方法。通过使用get_Geometry方法并结合特定条件筛选,成功获取了可用于创建尺寸标注的几何对象引用。

下图是两根详图构件,每个构件本身就是一条线。


我们想要做到这样:


我们知道NewDimension函数是这样的:

Dimension NewDimension(View view, 
    Line line, ReferenceArray references)
前面两个参数很容易理解,一个是要创建尺寸的视图,一个是尺寸线的位置,

那么最后一个ReferenceArray当然就是需要做标注的几何对象的引用了,问题是,如何获取这些引用?

很显然,通过(FamilyInstance.Location as LocationCurve).Curve.Reference拿到的结果是空。

我们就只能通过get_Geometry方法了。请看代码:

private static Line GetReferenceOfDetailComponent(Element element,
    View view)
{
    Options options = new Options();
    options.ComputeReferences = true;
    options.IncludeNonVisibleObjects = true;
    if (view != null)
        options.View = view;
    else
        options.DetailLevel = ViewDetailLevel.Fine;
    var geoElem = element.get_Geometry(options);
    foreach (var item in geoElem)
    {
        Line line = item as Line;
        if (line != null)
        {
            //in this case, code will never be executed to here
        }
        else
        {
            GeometryInstance geoInst = item as GeometryInstance;
            if (geoInst != null)
            {
                GeometryElement geoElemTmp = 
                    geoInst.GetSymbolGeometry();
                foreach (GeometryObject geomObjTmp in geoElemTmp)
                {
                    Line line2 = geomObjTmp as Line;
                    if (line2 != null)
                    {
                        //check if it is what you want
                        if (line2.GraphicsStyleId.IntegerValue == 355)
                        {
                            return line2;
                        }
                    }
                }
            }
        }
    }
    return null;
}

注意:

  • Options.ComputeReferences必须为true,否是拿到的几何体的Reference都将是null
  • 如果遍历GeometryElement的时候,碰到GeometryInstance,那么需要调用GetSymbolGeometry,获取更多几何体,而不能调用GetInstanceGeometry,因为后者得到的几何体也是无法创建Dimension的



using System; using System.Collections.Generic; using System.IO; using System.Linq; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; using Document = Autodesk.Revit.DB.Document; namespace SmartDimensionCommandNS { [Transaction(TransactionMode.Manual)] public class SmartDimensionCommand : IExternalCommand { private 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 }; try { if (!(activeView is ViewPlan || activeView is ViewSection || activeView.ViewType == ViewType.Elevation)) { throw new System.InvalidOperationException("不支持的视图类型,无法创建。"); } } catch (System.InvalidOperationException ex) { _logger.Log($"错误: {ex.Message}", LogLevel.Error); message = ex.Message; return Result.Failed; } _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, selectedElements); 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}"); } } } // ======================================== // ReferenceFactory(修正版,仅对齐标注和弧度标注,移除临时元素创建,直接查找真实Reference) // ======================================== public static class ReferenceFactory { // 获取元素的边(Edge)Reference,适用于对齐标注和弧度标注 public static Reference GetEdgeReference(Element element, Curve targetCurve) { Options opt = new Options { ComputeReferences = true }; GeometryElement geomElem = element.get_Geometry(opt); foreach (GeometryObject geomObj in geomElem) { if (geomObj is Solid solid) { foreach (Edge edge in solid.Edges) { Curve edgeCurve = edge.AsCurve(); if (IsCurveMatch(edgeCurve, targetCurve)) { return edge.Reference; } } } } return null; } // 判断两条曲线是否近似相等(支持Line和Arc) private static bool IsCurveMatch(Curve a, Curve b, double tol = 1e-6) { if (a is Line la && b is Line lb) { return (la.GetEndPoint(0).IsAlmostEqualTo(lb.GetEndPoint(0), tol) && la.GetEndPoint(1).IsAlmostEqualTo(lb.GetEndPoint(1), tol)) || (la.GetEndPoint(0).IsAlmostEqualTo(lb.GetEndPoint(1), tol) && la.GetEndPoint(1).IsAlmostEqualTo(lb.GetEndPoint(0), tol)); } if (a is Arc aa && b is Arc ab) { return aa.Center.IsAlmostEqualTo(ab.Center, tol) && Math.Abs(aa.Radius - ab.Radius) < tol; } return false; } private static bool IsAlmostEqualTo(this XYZ a, XYZ b, double tol = 1e-6) { return a.DistanceTo(b) < tol; } } // ======================================== // DimensionCreator(仅对齐标注和弧度标注,自动遍历元素) // ======================================== public class DimensionCreator { private readonly Document _doc; private readonly View _view; private readonly PluginConfig _config; private readonly Logger _logger; private readonly List<Element> _elements; public DimensionCreator(Document doc, View view, PluginConfig config, Logger logger, List<Element> elements) { _doc = doc; _view = view; _config = config; _logger = logger; _elements = elements; } public int CreateDimensions(List<Curve> curves) { int count = 0; foreach (var curve in curves) { foreach (var element in _elements) { if (curve is Line) { if (CreateAlignmentDimension(element, curve)) { count++; break; } } else if (curve is Arc arc) { if (CreateArcDimension(element, arc)) { count++; break; } } } } return count; } private bool CreateAlignmentDimension(Element element, Curve curve) { try { Reference edgeRef = ReferenceFactory.GetEdgeReference(element, curve); if (edgeRef == null) return false; XYZ p1 = curve.GetEndPoint(0); XYZ p2 = curve.GetEndPoint(1); Line dimLine = Line.CreateBound(p1, p2); ReferenceArray refArray = new ReferenceArray(); refArray.Append(edgeRef); Dimension dimension = _doc.Create.NewDimension(_view, dimLine, refArray); return true; } catch (Exception ex) { _logger.LogException($"创建对齐标注失败: {ex.Message}", ex); return false; } } private bool CreateArcDimension(Element element, Arc arc) { try { Reference edgeRef = ReferenceFactory.GetEdgeReference(element, arc); if (edgeRef == null) return false; XYZ arcMid = arc.Evaluate(0.5, true); _doc.Create.NewSpotElevation(_view, edgeRef, arcMid, arcMid, arcMid, arcMid, false); return true; } catch (Exception ex) { _logger.LogException($"创建弧度标注失败: {ex.Message}", ex); return false; } } } // ======================================== // 标注对齐方式枚举 // ======================================== public enum DimensionAlignment { Above, Below, Left, Right } } namespace SmartDimensionCommandNS { public class GeometryExtractor { private readonly Document _doc; private readonly PluginConfig _config; private readonly Logger _logger; public GeometryExtractor(Document doc, PluginConfig config, Logger logger) { _doc = doc; _config = config; _logger = logger; } public List<Curve> ExtractCurves(IEnumerable<ElementId> elementIds, View view) { var curves = new List<Curve>(); foreach (var id in elementIds) { var element = _doc.GetElement(id); if (element == null || !element.IsValidObject) continue; var options = new Options { ComputeReferences = true }; var geometryElement = element.get_Geometry(options); foreach (var geomObj in geometryElement) { if (geomObj is Solid solid) { foreach (Edge edge in solid.Edges) { curves.Add(edge.AsCurve()); } } } } return curves; } } }这段代码有没有实际用处,对于使用revit的人来说能做什么
最新发布
06-13
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值