我想通过编程方式获取全部有接触的梁,不考虑它们之间的连接状态。用户首先选中一根梁,然后程序自动将所有有递归接触的梁(即级联方式接触)选中。
Jeremy
首先让我们讨论这些梁是处于连接状态的情况:你可以使用 Beam.LocationCurve.ElementsAtJoin 属性获取在一根梁的指定端点连接的所有梁。然后再遍历得到的梁的集合,对每根梁继续使用 Beam.LocationCurve.ElementsAtJoin 属性获取级联模式下新的连接梁的集合。你可以在 SDK 例程 TraverseSystem 中找到类似的处理机制,这个例程展示了在管道系统中如何使用 MEP 连接管理器(Connection Manager)来遍历所有处于连接状态的元素。
1. 维护三个梁列表
- 已经处理过的梁(已处理梁表)2. 选中一根梁添加到当前梁表
3. 如果当前梁表非空,则重复如下处理
- 将当前梁添加到已处理梁表/// <summary> /// 获取所有与元素“e”相邻的元素(排除已处理过的元素) /// </summary> void AddElementsIntersectingSphereAt( List<ElementId> neighbours, XYZ p, List<ElementId> visited, Document doc ) { Solid sphere = CreateSphereAt( doc.Application.Create, p, _sphere_radius ); ElementIntersectsSolidFilter intersectSphere = new ElementIntersectsSolidFilter( sphere ); FilteredElementCollector collector = new FilteredElementCollector( doc ) .WhereElementIsCurveDriven() // 可以处理任意 Location 为 LocationCurve 的元素 .OfCategory( _bic ) .Excluding( visited.Union<ElementId>( neighbours ).ToList<ElementId>() ) .WherePasses( intersectSphere ); neighbours.AddRange( collector.ToElementIds() ); } /// <summary> /// Determine all neighbouring elements close to /// the two ends of the current element 'e', /// skipping all previously visited ones. /// </summary> void AddConnectedElements( List<ElementId> neighbours, Element e, List<ElementId> visited ) { Location loc = e.Location; Debug.Print( string.Format( "current element {0} has location {1}", ElementDescription( e ), null == loc ? "<null>" : loc.GetType().Name ) ); LocationCurve lc = loc as LocationCurve; if( null != lc ) { Document doc = e.Document; Curve c = lc.Curve; XYZ p = c.get_EndPoint( 0 ); XYZ q = c.get_EndPoint( 1 ); AddElementsIntersectingSphereAt( neighbours, p, visited, doc ); AddElementsIntersectingSphereAt( neighbours, q, visited, doc ); } }
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; }
注意这个解决方案适用于所有基于曲线的元素。可以用于查找所有接触墙体、管线、管道等等场景。