Building Coder(Revit 二次开发)- 使用“实体相交(Solid Intersection)”机制过滤有接触的梁
原文链接:Filter for Touching Beams Using Solid Intersection
几何创建工具创建的临时实体(Solid)可以用于几何特征过滤器。
问题
我想通过编程方式获取全部有接触的梁,不考虑它们之间的连接状态。用户首先选中一根梁,然后程序自动将所有有递归接触的梁(即级联方式接触)选中。
Jeremy
首先让我们讨论这些梁是处于连接状态的情况:你可以使用 Beam.LocationCurve.ElementsAtJoin 属性获取在一根梁的指定端点连接的所有梁。然后再遍历得到的梁的集合,对每根梁继续使用 Beam.LocationCurve.ElementsAtJoin 属性获取级联模式下新的连接梁的集合。你可以在 SDK 例程 TraverseSystem 中找到类似的处理机制,这个例程展示了在管道系统中如何使用 MEP 连接管理器(Connection Manager)来遍历所有处于连接状态的元素。
然后回到你的需求:这些梁不是处于连接状态,而只是相互接触的。我们可以使用 ElementIntersectsSolidFilter,在一个由实体定义的空间区域中检测所有与该区域相交的元素。这个实体可以来自实际的 BIM 模型,也可以是临时创建的且只存在于内存中。
为了获取所有级联方式接触的梁,我们必须为每根梁都创建一个实体和 ElementIntersectsSolidFilter。如果你需求中的接触是指在任意位置(即不是在梁的两个端点),那么应该按照当前梁的形状创建一个形状拉伸实体,然后检测与该形状拉伸实体有任何空间相交或是足够接近的梁。如果你只关心有端点接触的梁,那可以简单地在当前梁的端点处创建一个球体。
这个操作应该递归地应用到所有找到的梁。当然,你必须将已经处理过的梁排除在外,否则会导致死循环。
以下是我考虑的实现流程:
1. 维护三个梁列表
- 已经处理过的梁(已处理梁表)- 正在被处理的梁(当前梁表)
- 与正在被处理的梁相邻的梁(相邻梁表)
2. 选中一根梁添加到当前梁表
3. 如果当前梁表非空,则重复如下处理
- 将当前梁添加到已处理梁表- 清空相邻梁表
- 将与当前梁有接触的所有梁添加到相邻梁表
- 将在上一步中找到的相邻梁表作为新的当前梁表
在下面的代码中,检测与指定梁接触的所有梁的代码在方法 AddConnectedElements() 中。该方法首先在梁的两个端点分别创建一个球体,然后创建一个与基于球体的空间相邻检测器,并将其应用到一个 ElementIntersectsSolidFilter 中。执行过滤器,并从过滤结果中删除已经处理过的梁,和已经找到的相邻梁,然后将最后结果添加到相邻梁表。
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements ){ UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Application app = uiapp.Application; CreationApp creapp = app.Create; Document doc = uidoc.Document; Selection sel = uidoc.Selection; Reference r = null; try { r = sel.PickObject( ObjectType.Element, "Please select a beam" ); } catch( RvtOperationCanceledException ) { return Result.Cancelled; } // 初始梁 Element start = doc.GetElement( r ); // 当前梁表(我们需要查找它们的相邻梁) List<ElementId> current = new List<ElementId>(); current.Add( start.Id ); // 已处理梁表 List<ElementId> visited = new List<ElementId>(); // 相邻梁表 List<ElementId> neighbours = new List<ElementId>(); // 递归调用 while( 0 < current.Count ) { // 记录已处理梁表 visited.AddRange( current ); neighbours.Clear(); // 查找当前梁表的相邻梁表(未处理) foreach( ElementId id in current ) { Element e = doc.GetElement( id ); AddConnectedElements( neighbours, e, visited ); } // 当前梁表处理完毕,找到相邻梁表成为下一次操作的当前梁表 // newly found become the next current ones current.Clear(); current.AddRange( neighbours ); } foreach( ElementId id in visited ) { uidoc.Selection.Elements.Add( doc.GetElement( id ) ); } return Result.Succeeded;}注意这个解决方案适用于所有基于曲线的元素。可以用于查找所有接触墙体、管线、管道等等场景。