如何快速检索指定Room内的ElevationMarker及相关视图?
针对Room内ElevationMarker查找的高效解决方案
核心问题解答
Revit API里没有直接对应ElementIntersectsSolidFilter、专门用于匹配Room内ElevationMarker的过滤器,但可以通过空间几何判断+高效过滤逻辑替代你当前的低效实现,同时兼容所有现有模型,不用依赖ExtensibleStorage。
现有代码的性能瓶颈
你当前的实现有两个关键性能问题:
- 创建临时视图本身会产生额外开销,而且通过视图ID收集元素相当于遍历视图内所有元素,模型大时这个范围太广
- 对每个标记逐个调用
get_BoundingBox和GetRoomAtPoint,这类几何操作的单次开销不低,批量调用时会被放大
优化后的实现思路
直接基于Room的几何范围过滤全局的ElevationMarker,步骤如下:
- 获取目标Room的几何边界(Solid)或边界框,先做粗筛
- 全局收集所有ElevationMarker(跳过类型),用几何过滤器缩小范围
- 对筛选后的标记做精确判断,确认是否属于目标Room
优化代码示例
using Autodesk.Revit.DB; public List<ElevationMarker> GetElevationMarkersInRoom(Room targetRoom, Document doc) { List<ElevationMarker> markersInRoom = new List<ElevationMarker>(); Phase roomPhase = targetRoom.Phase; // 1. 获取Room的Solid边界(用于精确相交判断) Solid roomSolid = null; IList<IList<BoundarySegment>> boundarySegments = targetRoom.GetBoundarySegments(new SpatialElementBoundaryOptions()); if (boundarySegments != null && boundarySegments.Count > 0) { List<CurveLoop> curveLoops = new List<CurveLoop>(); foreach (var segmentList in boundarySegments) { CurveLoop loop = new CurveLoop(); foreach (BoundarySegment seg in segmentList) { loop.Append(seg.GetCurve()); } curveLoops.Add(loop); } roomSolid = GeometryCreationUtilities.CreateExtrusionGeometry(curveLoops, XYZ.BasisZ, targetRoom.UnboundedHeight); } if (roomSolid == null) { // 如果无法获取Solid,退而求其次用Room的BoundingBox做初步过滤 BoundingBoxXYZ roomBB = targetRoom.get_BoundingBox(null); Outline roomOutline = new Outline(roomBB.Min, roomBB.Max); BoundingBoxIntersectsFilter bbFilter = new BoundingBoxIntersectsFilter(roomOutline); var candidateMarkers = new FilteredElementCollector(doc) .OfClass(typeof(ElevationMarker)) .WhereElementIsNotElementType() .WherePasses(bbFilter) .Cast<ElevationMarker>() .Where(e => e.HasElevations()); foreach (var marker in candidateMarkers) { // 获取ElevationMarker的插入点 XYZ markerLocation = marker.GetTransform().Origin; Room markerRoom = doc.GetRoomAtPoint(markerLocation, roomPhase); if (markerRoom != null && markerRoom.Id == targetRoom.Id) { markersInRoom.Add(marker); } } } else { // 用Solid相交过滤器做精确筛选 ElementIntersectsSolidFilter solidFilter = new ElementIntersectsSolidFilter(roomSolid); markersInRoom = new FilteredElementCollector(doc) .OfClass(typeof(ElevationMarker)) .WhereElementIsNotElementType() .WherePasses(solidFilter) .Cast<ElevationMarker>() .Where(e => e.HasElevations()) .ToList(); // 额外校验:避免Solid相交判断的误判(比如标记边界刚好触碰到Room) markersInRoom = markersInRoom.Where(m => { XYZ loc = m.GetTransform().Origin; Room r = doc.GetRoomAtPoint(loc, roomPhase); return r != null && r.Id == targetRoom.Id; }).ToList(); } return markersInRoom; }
额外说明
- 找到ElevationMarker后,可以通过
marker.GetAllElevations()获取关联的立面视图ID,再通过doc.GetElement(viewId)拿到视图对象进行重命名 - 若Room的Solid创建失败(比如复杂形状的Room),代码会自动降级到边界框过滤+点校验的逻辑,保证兼容性
- 相比你原来的实现,这个方案省去了临时视图的创建,且用过滤器先粗筛元素,大幅减少了后续需要做精确判断的元素数量,性能提升明显
内容的提问来源于stack exchange,提问作者Anthony Tiefenbach
相关产品推荐
相关产品推荐

