Files
RevitArchive/RevitAddins/Extensions.cs
2026-02-23 14:58:05 +08:00

567 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using RevitAddins;
using System;
using System.Collections.Generic;
using System.Linq;
namespace RevitAddins;
public static class Extensions
{
/// <summary>
/// 文档的收集器
/// </summary>
/// <param name="document"></param>
public static FilteredElementCollector OfCollector(this Document document) => document == null ? throw new ArgumentNullException(nameof(document), "文档为空") : new(document);
public static object GetValue(this Parameter parameter)
{
object result = null;
switch (parameter.StorageType)
{
case StorageType.None:
break;
case StorageType.Integer:
result = parameter.AsInteger();
break;
case StorageType.Double:
result = parameter.AsDouble();
break;
case StorageType.String:
//Revit数据库存储的值
var str = parameter.AsString();
if (string.IsNullOrEmpty(str))
{
//用户可见的前端显示,如根据单位设置而显示的值
result = parameter.AsValueString();
}
else
{
result = str;
}
break;
case StorageType.ElementId:
result = parameter.AsElementId();
break;
}
return result;
}
/// <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.Model, 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.Model } &&
// 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;
}
}
}