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的人来说能做什么
最新发布