以下是完整的 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
}你自己检查检查