Files
SzmediTools/Szmedi.Toolkit.Revit/RvExtensions/DocumentExtensions.cs

527 lines
17 KiB
C#
Raw Normal View History

2025-09-16 16:06:41 +08:00

using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
namespace Szmedi.Toolkit.RvExtensions;
public static class DocumentExtensions
{
/// <summary>
/// 文档的收集器
/// </summary>
/// <param name="document"></param>
public static FilteredElementCollector OfCollector(this Document document) => document == null ? throw new ArgumentNullException(nameof(document), "文档为空") : new(document);
/// <summary>
/// 类型的元素集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="doc"></param>
/// <returns></returns>
public static FilteredElementCollector QueryElementsByType<T>(this Document doc)
where T : Element
{
return doc.OfCollector().OfClass(typeof(T));
}
/// <summary>
/// 收集特定类别
/// </summary>
/// <param name="doc"></param>
/// <param name="builtInCategory"></param>
/// <returns></returns>
public static FilteredElementCollector QueryElementsByCategory(this Document doc, BuiltInCategory builtInCategory)
{
return doc.OfCollector().OfCategory(builtInCategory);
}
/// <summary>
/// 收集特定类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="doc"></param>
/// <param name="builtInCategory"></param>
/// <returns></returns>
public static FilteredElementCollector QueryElementsByTypeAndCategory<T>(this Document doc, BuiltInCategory builtInCategory)
where T : Element
{
return doc.OfCollector().OfClass(typeof(T)).OfCategory(builtInCategory);
}
public static FilteredElementCollector OfCollector(this View view)
{
//if (view == null)
//{
// throw new ArgumentNullException(nameof(view));
//}
//if (!view.IsTemplate)
//{
// return new FilteredElementCollector(view.doc, view.Id);
//}
return FilteredElementCollector.IsViewValidForElementIteration(view.Document, view.Id)
? new FilteredElementCollector(view.Document, view.Id)
: throw new ArgumentException("当前视图不可应用收集器");
}
/// <summary>
/// 收集当前平面视图的某类图元
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="view"></param>
/// <returns></returns>
public static FilteredElementCollector QueryInstancesByType<T>(this View view)
where T : Element
{
return view.OfCollector().OfClass(typeof(T)).WhereElementIsNotElementType();
}
/// <summary>
/// 收集当前平面视图的某类别图元
/// </summary>
/// <param name="view"></param>
/// <param name="builtInCategory"></param>
/// <returns></returns>
public static FilteredElementCollector QueryElementsByCategoryInView(this View view, BuiltInCategory builtInCategory)
{
return view.OfCollector().OfCategory(builtInCategory).WhereElementIsNotElementType();
}
/// <summary>
/// 收集当前平面视图的某类图元
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="view"></param>
/// <param name="builtInCategory"></param>
/// <returns></returns>
public static FilteredElementCollector QueryElementsByTypeAndCategory<T>(this View view, BuiltInCategory builtInCategory)
where T : Element
{
return view.OfCollector().OfClass(typeof(T)).OfCategory(builtInCategory).WhereElementIsNotElementType();
}
/// <summary>
/// 过滤项目文件独立模型元素,包含依附在主体上的元素,如楼板边缘、屋顶边缘、墙饰条、封檐板,檐沟等等
/// </summary>
/// <returns>元素集合</returns>
public static FilteredElementCollector OfParentModelCollector(this Document doc)
{
var col = doc.OfCollector()
.WhereElementIsNotElementType()
.Where(
e => e is TopographySurface ||
e is DirectShape ||
(e.CanHaveTypeAssigned()
&& e.IsValidObject
&& e.HasPhases()
&& e.ArePhasesModifiable()
&& e.get_BoundingBox(null) != null
&& e.Category is { CategoryType: CategoryType.Model }
&& (e is HostObject || e.Category.Parent == null)
&& e is not Panel
&& e is not Mullion
&& e is not RevitLinkInstance)
).Select(e => e.Id).ToList();
if (col.Count == 0)
{
return null;
}
return new FilteredElementCollector(doc, col).WhereElementIsNotElementType();
}
/// <summary>
/// 过滤项目文件的所有模型元素
/// </summary>
/// <returns>元素集合</returns>
public static FilteredElementCollector OfAllModelCollector(this Document doc)
{
if (doc == null)
{
throw new ArgumentNullException(nameof(doc), "文档为空");
}
var col = doc.OfCollector()
.WhereElementIsNotElementType()
.Where(
e => e is TopographySurface ||
e is DirectShape ||
(e.CanHaveTypeAssigned() &&
e.IsValidObject &&
e.HasPhases() &&
e.ViewSpecific == false &&
e.Category is { CategoryType: CategoryType.Model, AllowsBoundParameters: true } &&
e.get_BoundingBox(null) != null &&
e is not RevitLinkInstance)).Select(e => e.Id).ToList();
if (col.Count == 0)
{
return null;
}
return new FilteredElementCollector(doc, col).WhereElementIsNotElementType();
}
///// <summary>
///// 获取所有最高层级的模型元素,不包含子模型
///// </summary>
///// <param name="doc"></param>
///// <returns></returns>
//public static IEnumerable<Element> OfModelElements(this Document doc)
//{
// return doc.OfCollector()
// .WhereElementIsNotElementType()
// .Where(
// e => e is TopographySurface || (
// e.CanHaveTypeAssigned()
// && e.IsValidObject
// && e.get_BoundingBox(null) != null
// && e.HasPhases()
// && e.ViewSpecific == false
// && e.Category is { Parent: null, CategoryType: CategoryType.FacilityNumber, AllowsBoundParameters: true }
// && e is not Panel
// && e is not Mullion
// && e is not RevitLinkInstance)
// );
//}
///// <summary>
///// 所有元素不包括幕墙嵌板,幕墙竖梃、依附图元等等
///// </summary>
///// <param name="doc"></param>
///// <returns></returns>
//public static FilteredElementCollector OfModelCollector(this Document doc)
//{
// if (doc == null)
// {
// throw new ArgumentNullException(nameof(doc), "文档为空");
// }
// var li = doc.OfCollector().WhereElementIsNotElementType()
// .Where(
// e => e is TopographySurface ||
// (e.CanHaveTypeAssigned() &&
// e.HasPhases() &&
// e.Category is { Parent: null, CategoryType: CategoryType.FacilityNumber } &&
// e is not Panel &&
// e is not Mullion &&
// e is not RevitLinkInstance)).Select(e => e.Id).ToList();
// return new FilteredElementCollector(doc, li).WhereElementIsNotElementType();
//}
/// <summary>
/// 获取对应类型的元素收集器
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="doc"></param>
/// <returns></returns>
public static IEnumerable<T> OfType<T>(this Document doc)
where T : Element => doc.OfCollector().OfClass(typeof(T)).OfType<T>();
public static FilteredElementCollector OfClass<T>(this Document doc)
where T : Element
{
return doc.OfCollector().OfClass(typeof(T));
}
/// <summary>
/// 射线法查找所有的Element
/// </summary>
/// <param name="doc">Dcument</param>
/// <param name="filter">例如ElementClassFilter filter = new ElementClassFilter(typeof(CableTray))</param>
/// <param name="targetRef">目标对象</param>
/// <param name="center">射源</param>
/// <param name="direction">方向</param>
/// <returns>返回该射线</returns>
public static IList<Element> XRayFindAll(
this Document doc,
ElementFilter filter,
FindReferenceTarget targetRef,
XYZ center,
XYZ direction
)
{
FilteredElementCollector collector = new(doc);
Func<View3D, bool> isNotTemplate = v3 => !v3.IsTemplate;
var view3D = collector.OfClass(typeof(View3D)).Cast<View3D>().First(isNotTemplate);
ReferenceIntersector refIntersector = new(filter, targetRef, view3D);
var refWithContexts = refIntersector.Find(center, direction);
if (null == refWithContexts)
{
return null;
}
IList<Element> resultElements = [];
foreach (var rwc in refWithContexts)
{
var reference = rwc.GetReference();
var hitElement = doc.GetElement(reference);
if (hitElement != null)
{
resultElements.Add(hitElement);
}
}
return resultElements;
}
/// <summary>
/// 获取标高范围框
/// </summary>
/// <remarks>最低标高除了包含以上部分,还包含以下部分,最高标高包含以上部分</remarks>
/// <param name="doc"></param>
/// <returns></returns>
public static Dictionary<Level, Outline> GetLevelRanges(this Document doc)
{
var levels = doc.OfType<Level>().Cast<Level>().OrderBy(l => l.Elevation).ToList();
Dictionary<Level, Outline> levelOutlines = [];
//获取标高范围
for (var i = 0; i < levels.Count; i++)
{
var baseLevel = levels[i];
XYZ min = new(double.MinValue, double.MinValue, baseLevel.Elevation);
XYZ max;
Outline outline;
if (i == 0)
{
min = new XYZ(double.MinValue, double.MinValue, double.MinValue);
var topLevel = levels[i + 1];
max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation);
outline = new Outline(min, max);
}
else if (i < levels.Count - 1)
{
var topLevel = levels[i + 1];
max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation);
outline = new Outline(min, max);
}
else//最后一个标高以上
{
max = new XYZ(double.MaxValue, double.MaxValue, double.MaxValue);
outline = new Outline(min, max);
}
levelOutlines.Add(baseLevel, outline);
}
return levelOutlines;
}
/// <summary>
/// 射线法查找最近的Element
/// </summary>
/// <param name="doc">Dcument</param>
/// <param name="filter">例如ElementClassFilter filter = new ElementClassFilter(typeof(CableTray))</param>
/// <param name="targetRef">目标对象</param>
/// <param name="center">射源</param>
/// <param name="direction">方向</param>
/// <param name="hitElement">被击中的Element</param>
/// <returns>返回该射线</returns>
public static Line XRayFindNearest(
this Document doc,
ElementFilter filter,
FindReferenceTarget targetRef,
XYZ center,
XYZ direction,
ref Element hitElement
)
{
FilteredElementCollector collector = new(doc);
var view3D = collector.OfClass(typeof(View3D)).Cast<View3D>().First(v3 => !v3.IsTemplate);
var rwc = new ReferenceIntersector(filter, targetRef, view3D).FindNearest(center, direction);
if (null == rwc)
{
return null;
}
var reference = rwc.GetReference();
var intersection = reference.GlobalPoint;
hitElement = doc.GetElement(reference);
Line result = null;
if (!center.IsAlmostEqualTo(intersection))
{
result = Line.CreateBound(center, intersection);
}
else
{
hitElement = null;
}
return result;
}
public static TResult Invoke<TResult>(this Document doc, Func<Transaction, TResult> func, string name = "default")
{
using var tr = new Transaction(doc, name);
tr.Start();
var result = func(tr);
var status = tr.GetStatus();
switch (status)
{
case TransactionStatus.Started:
tr.Commit();
return result;
case TransactionStatus.Committed:
case TransactionStatus.RolledBack:
return result;
case TransactionStatus.Error:
tr.RollBack();
return result;
default:
return result;
}
}
public static TResult InvokeGroup<TResult>(this Document doc, Func<TransactionGroup, TResult> func, string name = "default")
{
using var tg = new TransactionGroup(doc, name);
tg.Start();
var result = func(tg);
var status = tg.GetStatus();
switch (status)
{
case TransactionStatus.Started:
tg.Assimilate();
//tr.Commit();
return result;
case TransactionStatus.Committed:
case TransactionStatus.RolledBack:
return result;
case TransactionStatus.Error:
tg.RollBack();
return result;
default:
return result;
}
}
public static TResult InvokeSub<TResult>(this Document doc, Func<SubTransaction, TResult> func)
{
using var st = new SubTransaction(doc);
st.Start();
var result = func(st);
var status = st.GetStatus();
switch (status)
{
case TransactionStatus.Started:
st.Commit();
return result;
case TransactionStatus.Committed:
case TransactionStatus.RolledBack:
return result;
case TransactionStatus.Error:
st.RollBack();
return result;
default:
return result;
}
}
//private static void UsingThisClass(doc doc)
//{
// //无返回值
// doc.Invoke(m => { }, "x");
// //有返回值
// doc.Invoke<Level>(m =>
// {
// return Level.Create(doc, 5);
// }, "x");
// doc.InvokeGroup(m => { doc.Invoke(mn => { }, "x"); }, "x");
// doc.InvokeGroup<Level>(m => { doc.Invoke(mn => { }, "x"); doc.Invoke(mn => { }, "Y"); return Level.Create(doc, 5); }, "x");
// doc.InvokeSub(m => { });
// doc.InvokeSub<Level>(m => { return Level.Create(doc, 5); });
//}
public static void Invoke(this Document doc, Action<Transaction> action, string name = "default")
{
using var tr = new Transaction(doc, name);
tr.Start();
action(tr);
var status = tr.GetStatus();
switch (status)
{
case TransactionStatus.Started:
tr.Commit();
return;
case TransactionStatus.Committed:
case TransactionStatus.RolledBack:
return;
case TransactionStatus.Error:
tr.RollBack();
return;
default:
return;
}
}
public static void InvokeGroup(this Document doc, Action<TransactionGroup> action, string name = "default")
{
using var tg = new TransactionGroup(doc, name);
tg.Start();
action(tg);
var status = tg.GetStatus();
switch (status)
{
case TransactionStatus.Started:
//tr.Commit();
tg.Assimilate();
return;
case TransactionStatus.Committed:
case TransactionStatus.RolledBack:
break;
case TransactionStatus.Error:
tg.RollBack();
return;
default:
return;
}
}
public static void InvokeSub(this Document doc, Action<SubTransaction> action)
{
using var st = new SubTransaction(doc);
st.Start();
action(st);
var status = st.GetStatus();
switch (status)
{
case TransactionStatus.Started:
st.Commit();
return;
case TransactionStatus.Committed:
case TransactionStatus.RolledBack:
break;
case TransactionStatus.Error:
st.RollBack();
return;
default:
return;
}
}
}