567 lines
18 KiB
C#
567 lines
18 KiB
C#
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|