508 lines
18 KiB
C#
508 lines
18 KiB
C#
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
|
|||
|
|
using Autodesk.Revit.DB;
|
|||
|
|
|
|||
|
|
using EPPlus.Core.Extensions.Attributes;
|
|||
|
|
|
|||
|
|
namespace Szmedi.RvKits.ModelManager
|
|||
|
|
{
|
|||
|
|
// ==========================================
|
|||
|
|
// 1. 数据模型定义 (Models)
|
|||
|
|
// ==========================================
|
|||
|
|
|
|||
|
|
public enum DiffType { Added, Deleted, Modified }
|
|||
|
|
|
|||
|
|
public class LocationDetail
|
|||
|
|
{
|
|||
|
|
public string OldValue { get; set; } // 修改前的坐标 (新增时为null)
|
|||
|
|
public string NewValue { get; set; } // 修改后的坐标 / 新增时的当前坐标
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class ParamDetail
|
|||
|
|
{
|
|||
|
|
public string ParamName { get; set; }
|
|||
|
|
public string OldValue { get; set; }
|
|||
|
|
public string NewValue { get; set; }
|
|||
|
|
|
|||
|
|
public ParamDetail(string name, string oldVal, string newVal)
|
|||
|
|
{
|
|||
|
|
ParamName = name;
|
|||
|
|
OldValue = oldVal;
|
|||
|
|
NewValue = newVal;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 构件状态快照 (对应 Excel 表格中的半边数据)
|
|||
|
|
/// </summary>
|
|||
|
|
public class ComponentState
|
|||
|
|
{
|
|||
|
|
public string ElementId { get; set; } = "无";
|
|||
|
|
public string TypeName { get; set; } = "无";
|
|||
|
|
public string DesignProps { get; set; } = "无"; // 设计属性 (多行文本)
|
|||
|
|
public string QuantityProps { get; set; } = "无"; // 出量属性 (体积/面积)
|
|||
|
|
public string Coordinates { get; set; } = "无"; // 坐标 (X/Y/Z)
|
|||
|
|
|
|||
|
|
public bool IsEmpty => ElementId == "无";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 报表行数据
|
|||
|
|
/// </summary>
|
|||
|
|
public class ReportRow
|
|||
|
|
{
|
|||
|
|
public int Index { get; set; }
|
|||
|
|
public string ChangeType { get; set; } // 新增/删除/修改
|
|||
|
|
public ComponentState After { get; set; } = new ComponentState(); // 变更后
|
|||
|
|
public ComponentState Before { get; set; } = new ComponentState(); // 变更前
|
|||
|
|
}
|
|||
|
|
public class ElementDiffInfo
|
|||
|
|
{
|
|||
|
|
[ExcelTableColumn("图元ID")]
|
|||
|
|
public ElementId ElementId { get; set; }
|
|||
|
|
public string UniqueId { get; set; }
|
|||
|
|
public string CategoryName { get; set; }
|
|||
|
|
[ExcelTableColumn("类型")]
|
|||
|
|
public string Name { get; set; } // 族名称或类型名称
|
|||
|
|
[ExcelTableColumn("修改类型")]
|
|||
|
|
public DiffType Status { get; set; }
|
|||
|
|
|
|||
|
|
// 位置变更详情 (新增或修改)
|
|||
|
|
[ExcelTableColumn("坐标")]
|
|||
|
|
public LocationDetail LocationChange { get; set; }
|
|||
|
|
|
|||
|
|
[ExcelTableColumn("设计属性")]
|
|||
|
|
// 参数变更详情列表
|
|||
|
|
public List<ParamDetail> ParamChanges { get; set; } = new List<ParamDetail>();
|
|||
|
|
[ExcelTableColumn("出量属性")]
|
|||
|
|
public string CalculatedParameter { get; set; }
|
|||
|
|
public bool HasChanges => LocationChange != null || ParamChanges.Count > 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==========================================
|
|||
|
|
// 2. 核心对比逻辑 (ProjectComparer)
|
|||
|
|
// ==========================================
|
|||
|
|
|
|||
|
|
public class ProjectComparerTest
|
|||
|
|
{
|
|||
|
|
private List<string> _targetParams;
|
|||
|
|
private const double Tolerance = 0.0001; // 几何容差 (英尺)
|
|||
|
|
|
|||
|
|
public ProjectComparerTest(List<string> targetParams)
|
|||
|
|
{
|
|||
|
|
_targetParams = targetParams;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<ElementDiffInfo> CompareDocuments(Document oldDoc, Document newDoc)
|
|||
|
|
{
|
|||
|
|
var results = new List<ElementDiffInfo>();
|
|||
|
|
|
|||
|
|
// 1. 获取构件字典,使用 UniqueId 进行匹配
|
|||
|
|
var oldMap = GetElementMap(oldDoc);
|
|||
|
|
var newMap = GetElementMap(newDoc);
|
|||
|
|
|
|||
|
|
// 2. 遍历新文档 -> 检查 [新增] 和 [修改]
|
|||
|
|
foreach (var kvp in newMap)
|
|||
|
|
{
|
|||
|
|
string uid = kvp.Key;
|
|||
|
|
Element newElem = kvp.Value;
|
|||
|
|
|
|||
|
|
if (!oldMap.ContainsKey(uid))
|
|||
|
|
{
|
|||
|
|
// ================= [新增] =================
|
|||
|
|
var diffInfo = new ElementDiffInfo
|
|||
|
|
{
|
|||
|
|
ElementId = newElem.Id,
|
|||
|
|
UniqueId = uid,
|
|||
|
|
CategoryName = newElem.Category?.Name,
|
|||
|
|
Name = newElem.Name,
|
|||
|
|
Status = DiffType.Added
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取坐标:优先定位点,其次包围盒底部中心
|
|||
|
|
string locStr = GetSmartCoordinate(newElem);
|
|||
|
|
if (!string.IsNullOrEmpty(locStr))
|
|||
|
|
{
|
|||
|
|
// 新增时,将坐标存入 NewValue
|
|||
|
|
diffInfo.LocationChange = new LocationDetail
|
|||
|
|
{
|
|||
|
|
OldValue = null,
|
|||
|
|
NewValue = locStr
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
results.Add(diffInfo);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// ================= [修改] =================
|
|||
|
|
Element oldElem = oldMap[uid];
|
|||
|
|
|
|||
|
|
// A. 检查位置 (仅检查 LocationPoint 类型的变化)
|
|||
|
|
LocationDetail locDiff = CheckPointLocationChange(oldElem, newElem);
|
|||
|
|
|
|||
|
|
// B. 检查参数 (包含 Name 和 用户自定义参数)
|
|||
|
|
List<ParamDetail> paramDiffs = CheckParamChanges(oldElem, newElem);
|
|||
|
|
|
|||
|
|
// 只有当 位置变了 或 参数变了 时才记录
|
|||
|
|
if (locDiff != null || paramDiffs.Count > 0)
|
|||
|
|
{
|
|||
|
|
results.Add(new ElementDiffInfo
|
|||
|
|
{
|
|||
|
|
ElementId = newElem.Id,
|
|||
|
|
UniqueId = uid,
|
|||
|
|
CategoryName = newElem.Category?.Name,
|
|||
|
|
Name = newElem.Name,
|
|||
|
|
Status = DiffType.Modified,
|
|||
|
|
LocationChange = locDiff, // 包含 OldValue 和 NewValue
|
|||
|
|
ParamChanges = paramDiffs
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 遍历旧文档 -> 检查 [删除]
|
|||
|
|
foreach (var kvp in oldMap)
|
|||
|
|
{
|
|||
|
|
if (!newMap.ContainsKey(kvp.Key))
|
|||
|
|
{
|
|||
|
|
// ================= [删除] =================
|
|||
|
|
results.Add(new ElementDiffInfo
|
|||
|
|
{
|
|||
|
|
ElementId = kvp.Value.Id,
|
|||
|
|
UniqueId = kvp.Key,
|
|||
|
|
CategoryName = kvp.Value.Category?.Name,
|
|||
|
|
Name = kvp.Value.Name,
|
|||
|
|
Status = DiffType.Deleted
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --------------------------------------------------------
|
|||
|
|
// 辅助方法区域
|
|||
|
|
// --------------------------------------------------------
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 智能获取构件坐标 (用于新增构件的定位描述)
|
|||
|
|
/// </summary>
|
|||
|
|
private string GetSmartCoordinate(Element elem)
|
|||
|
|
{
|
|||
|
|
XYZ p = null;
|
|||
|
|
|
|||
|
|
// 策略1: 如果是基于点的构件 (柱、门、窗、家具等)
|
|||
|
|
if (elem.Location is LocationPoint lp)
|
|||
|
|
{
|
|||
|
|
p = lp.Point;
|
|||
|
|
}
|
|||
|
|
// 策略2: 如果是基于线或轮廓的构件 (墙、梁、楼板),取包围盒底部中心
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
BoundingBoxXYZ box = elem.get_BoundingBox(null);
|
|||
|
|
if (box != null)
|
|||
|
|
{
|
|||
|
|
double cx = (box.Min.X + box.Max.X) / 2.0;
|
|||
|
|
double cy = (box.Min.Y + box.Max.Y) / 2.0;
|
|||
|
|
double cz = box.Min.Z; // 底部 Z
|
|||
|
|
p = new XYZ(cx, cy, cz);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return p != null ? FormatPoint(p) : "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检查位置变化 (严格模式:仅检查 Point 类型)
|
|||
|
|
/// </summary>
|
|||
|
|
private LocationDetail CheckPointLocationChange(Element oldElem, Element newElem)
|
|||
|
|
{
|
|||
|
|
// 只有当两个版本都是 LocationPoint 时才对比位置
|
|||
|
|
// 避免对比墙体等 LocationCurve 导致的复杂性
|
|||
|
|
if (oldElem.Location is LocationPoint lpOld && newElem.Location is LocationPoint lpNew)
|
|||
|
|
{
|
|||
|
|
// 1. 比较坐标
|
|||
|
|
bool posChanged = !lpOld.Point.IsAlmostEqualTo(lpNew.Point, Tolerance);
|
|||
|
|
|
|||
|
|
// 2. 比较旋转 (如果不关心旋转可注释掉)
|
|||
|
|
bool rotChanged = Math.Abs(lpOld.Rotation - lpNew.Rotation) > Tolerance;
|
|||
|
|
|
|||
|
|
if (posChanged || rotChanged)
|
|||
|
|
{
|
|||
|
|
return new LocationDetail
|
|||
|
|
{
|
|||
|
|
OldValue = FormatPoint(lpOld.Point),
|
|||
|
|
NewValue = FormatPoint(lpNew.Point)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null; // 无变化或不支持的定位类型
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检查参数变化 (包含构件名和自定义参数)
|
|||
|
|
/// </summary>
|
|||
|
|
private List<ParamDetail> CheckParamChanges(Element oldElem, Element newElem)
|
|||
|
|
{
|
|||
|
|
var list = new List<ParamDetail>();
|
|||
|
|
|
|||
|
|
// 1. 检查构件名 (Name)
|
|||
|
|
if (oldElem.Name != newElem.Name)
|
|||
|
|
{
|
|||
|
|
list.Add(new ParamDetail("构件名", oldElem.Name, newElem.Name));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 检查自定义参数
|
|||
|
|
foreach (var paramName in _targetParams)
|
|||
|
|
{
|
|||
|
|
string vOld = GetParamValueString(oldElem, paramName);
|
|||
|
|
string vNew = GetParamValueString(newElem, paramName);
|
|||
|
|
|
|||
|
|
if (vOld != vNew)
|
|||
|
|
{
|
|||
|
|
list.Add(new ParamDetail(paramName, vOld, vNew));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return list;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取参数值的安全字符串形式
|
|||
|
|
/// </summary>
|
|||
|
|
private string GetParamValueString(Element elem, string paramName)
|
|||
|
|
{
|
|||
|
|
Parameter p = elem.LookupParameter(paramName);
|
|||
|
|
if (p == null) return "<null>"; // 或者返回 ""
|
|||
|
|
|
|||
|
|
// 优先返回用户可见的格式化字符串 (如 "1200 mm")
|
|||
|
|
if (p.StorageType == StorageType.String)
|
|||
|
|
return p.AsString() ?? "";
|
|||
|
|
|
|||
|
|
string val = p.AsValueString();
|
|||
|
|
if (!string.IsNullOrEmpty(val)) return val;
|
|||
|
|
|
|||
|
|
// 如果 AsValueString 为空,读取底层数据
|
|||
|
|
switch (p.StorageType)
|
|||
|
|
{
|
|||
|
|
case StorageType.Integer: return p.AsInteger().ToString();
|
|||
|
|
case StorageType.Double: return p.AsDouble().ToString("F2");
|
|||
|
|
case StorageType.ElementId: return p.AsElementId().ToString();
|
|||
|
|
default: return "";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取需要对比的构件集合
|
|||
|
|
/// </summary>
|
|||
|
|
private Dictionary<string, Element> GetElementMap(Document doc)
|
|||
|
|
{
|
|||
|
|
// 过滤规则:非类型、非视图相关、有材质(通常代表实体)
|
|||
|
|
return new FilteredElementCollector(doc)
|
|||
|
|
.WhereElementIsNotElementType()
|
|||
|
|
.WhereElementIsViewIndependent()
|
|||
|
|
.Where(e => e.Category != null && e.Category.HasMaterialQuantities)
|
|||
|
|
.ToDictionary(e => e.UniqueId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 统一坐标格式化
|
|||
|
|
/// </summary>
|
|||
|
|
private string FormatPoint(XYZ p)
|
|||
|
|
{
|
|||
|
|
// 内部单位是英尺,如需毫米显示请在此处转换
|
|||
|
|
// 例如: double x = p.X * 304.8;
|
|||
|
|
return $"({p.X:F1}, {p.Y:F1}, {p.Z:F1})";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class ProjectComparer
|
|||
|
|
{
|
|||
|
|
public ProjectComparer(List<string> designParams, List<string> quantityParams)
|
|||
|
|
{
|
|||
|
|
this.designParams = designParams;
|
|||
|
|
this.quantityParams = quantityParams;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//设计参数
|
|||
|
|
private readonly List<string> designParams;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 配置:需要在“出量属性”栏显示的参数
|
|||
|
|
private readonly List<string> quantityParams;
|
|||
|
|
|
|||
|
|
public List<ReportRow> CompareDocuments(Document oldDoc, Document newDoc)
|
|||
|
|
{
|
|||
|
|
var rows = new List<ReportRow>();
|
|||
|
|
var oldMap = GetElementMap(oldDoc);
|
|||
|
|
var newMap = GetElementMap(newDoc);
|
|||
|
|
|
|||
|
|
int indexCounter = 1;
|
|||
|
|
|
|||
|
|
// --- A. 遍历新文档 (查找 [新增] 和 [修改]) ---
|
|||
|
|
foreach (var kvp in newMap)
|
|||
|
|
{
|
|||
|
|
string uid = kvp.Key;
|
|||
|
|
Element newElem = kvp.Value;
|
|||
|
|
|
|||
|
|
if (!oldMap.ContainsKey(uid))
|
|||
|
|
{
|
|||
|
|
// === 新增构件 ===
|
|||
|
|
rows.Add(new ReportRow
|
|||
|
|
{
|
|||
|
|
Index = indexCounter++,
|
|||
|
|
ChangeType = "新增构件",
|
|||
|
|
After = ExtractState(newElem),
|
|||
|
|
Before = new ComponentState { ElementId = "无" } // 空状态
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// === 修改构件 ===
|
|||
|
|
Element oldElem = oldMap[uid];
|
|||
|
|
|
|||
|
|
// 判断是否有实质性修改 (参数或位置)
|
|||
|
|
if (IsElementModified(oldElem, newElem))
|
|||
|
|
{
|
|||
|
|
rows.Add(new ReportRow
|
|||
|
|
{
|
|||
|
|
Index = indexCounter++,
|
|||
|
|
ChangeType = "修改构件",
|
|||
|
|
After = ExtractState(newElem),
|
|||
|
|
Before = ExtractState(oldElem)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- B. 遍历旧文档 (查找 [删除]) ---
|
|||
|
|
foreach (var kvp in oldMap)
|
|||
|
|
{
|
|||
|
|
if (!newMap.ContainsKey(kvp.Key))
|
|||
|
|
{
|
|||
|
|
// === 删除构件 ===
|
|||
|
|
rows.Add(new ReportRow
|
|||
|
|
{
|
|||
|
|
Index = indexCounter++,
|
|||
|
|
ChangeType = "删除构件",
|
|||
|
|
After = new ComponentState { ElementId = "无" }, // 空状态
|
|||
|
|
Before = ExtractState(kvp.Value)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return rows;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 提取构件信息为状态对象 ---
|
|||
|
|
private ComponentState ExtractState(Element e)
|
|||
|
|
{
|
|||
|
|
var state = new ComponentState
|
|||
|
|
{
|
|||
|
|
ElementId = e.Id.ToString(),
|
|||
|
|
TypeName = e.Name // 这里的Name通常是族类型名称
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 1. 提取设计属性 (拼接成换行字符串)
|
|||
|
|
var sbDesign = new StringBuilder();
|
|||
|
|
foreach (var paramName in designParams)
|
|||
|
|
{
|
|||
|
|
string val = GetParamValue(e, paramName);
|
|||
|
|
if (!string.IsNullOrEmpty(val))
|
|||
|
|
{
|
|||
|
|
// Excel 单元格内换行使用 Environment.NewLine
|
|||
|
|
sbDesign.AppendLine($"{paramName}: {val}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
state.DesignProps = sbDesign.Length > 0 ? sbDesign.ToString().TrimEnd() : "";
|
|||
|
|
|
|||
|
|
// 2. 提取出量属性
|
|||
|
|
var sbQty = new StringBuilder();
|
|||
|
|
foreach (var paramName in quantityParams)
|
|||
|
|
{
|
|||
|
|
string val = GetParamValue(e, paramName);
|
|||
|
|
// 排除 0.00 的情况
|
|||
|
|
if (!string.IsNullOrEmpty(val) && val != "0.00" && val != "0")
|
|||
|
|
{
|
|||
|
|
sbQty.AppendLine($"{paramName}: {val}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
state.QuantityProps = sbQty.Length > 0 ? sbQty.ToString().TrimEnd() : "";
|
|||
|
|
|
|||
|
|
// 3. 提取坐标 (竖排显示)
|
|||
|
|
state.Coordinates = GetFormattedCoordinates(e);
|
|||
|
|
|
|||
|
|
return state;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 辅助:坐标格式化 (核心逻辑:有定位点取点,没点取包围盒) ---
|
|||
|
|
private string GetFormattedCoordinates(Element e)
|
|||
|
|
{
|
|||
|
|
XYZ p = null;
|
|||
|
|
|
|||
|
|
// 策略1: 基于点 (柱、门、窗、家具)
|
|||
|
|
if (e.Location is LocationPoint lp)
|
|||
|
|
{
|
|||
|
|
p = lp.Point;
|
|||
|
|
}
|
|||
|
|
// 策略2: 基于线或形状 (墙、梁、板) -> 取包围盒底部中心
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
var box = e.get_BoundingBox(null);
|
|||
|
|
if (box != null)
|
|||
|
|
{
|
|||
|
|
double cx = (box.Min.X + box.Max.X) / 2.0;
|
|||
|
|
double cy = (box.Min.Y + box.Max.Y) / 2.0;
|
|||
|
|
double cz = box.Min.Z;
|
|||
|
|
p = new XYZ(cx, cy, cz);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (p == null) return "无";
|
|||
|
|
|
|||
|
|
// 格式化为 Excel 竖排效果,并转换单位 (英尺 -> 毫米)
|
|||
|
|
double toMm = 304.8;
|
|||
|
|
return $"X: {(p.X * toMm):F2}\nY: {(p.Y * toMm):F2}\nZ: {(p.Z * toMm):F2}";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 辅助:判断是否修改 ---
|
|||
|
|
private bool IsElementModified(Element oldE, Element newE)
|
|||
|
|
{
|
|||
|
|
// 1. 名字变了
|
|||
|
|
if (oldE.Name != newE.Name) return true;
|
|||
|
|
|
|||
|
|
// 2. 坐标变了
|
|||
|
|
if (GetFormattedCoordinates(oldE) != GetFormattedCoordinates(newE)) return true;
|
|||
|
|
|
|||
|
|
// 3. 关键参数变了 (可选:遍历 _designParams 检查)
|
|||
|
|
// 这里简单示例:如果提取出的设计属性字符串不一致,就算修改
|
|||
|
|
// 实际为了性能,建议在这里写单独的参数对比循环
|
|||
|
|
var s1 = ExtractState(oldE).DesignProps;
|
|||
|
|
var s2 = ExtractState(newE).DesignProps;
|
|||
|
|
if (s1 != s2) return true;
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 辅助:获取参数值 ---
|
|||
|
|
private string GetParamValue(Element e, string name)
|
|||
|
|
{
|
|||
|
|
Parameter p = e.LookupParameter(name);
|
|||
|
|
if (p == null) return "";
|
|||
|
|
if (p.StorageType == StorageType.String) return p.AsString();
|
|||
|
|
return p.AsValueString(); // AsValueString 会带单位
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 辅助:获取元素字典 ---
|
|||
|
|
private Dictionary<string, Element> GetElementMap(Document doc)
|
|||
|
|
{
|
|||
|
|
return new FilteredElementCollector(doc)
|
|||
|
|
.WhereElementIsNotElementType()
|
|||
|
|
.WhereElementIsViewIndependent()
|
|||
|
|
.Where(e => e.Category != null && e.Category.HasMaterialQuantities) // 简单的实体过滤
|
|||
|
|
.ToDictionary(e => e.UniqueId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|