# 多层建筑楼层过滤优化方案 ## 背景 在多层建筑的路径规划中,当前系统处理所有楼层的障碍物,导致大量无关数据参与计算。如果能快速过滤掉其他楼层的障碍物,性能提升会非常显著。 ## 当前实现状态 ### 1. 楼层过滤已被禁用 ```csharp // GridMapGenerator.cs line 157-158 // TODO: 楼层过滤功能已暂时注释,需要时可重新启用 var modelItems = allModelItems; // 直接使用所有模型项,不进行楼层过滤 ``` ### 2. 现有方法的局限性 - **基于属性的过滤**(`ApplyFloorAwareFilteringWithSearchAPI`) - 依赖模型的"层"属性 - 不是所有BIM模型都有规范的楼层属性 - 需要手动维护属性映射 - **简化高程过滤**(`ApplySimplifiedFloorFiltering`) - 使用±10米容差 - 过于粗糙,会包含2-3个楼层 - 无法精确定位单个楼层 ## 优化方案 ### 方案1:基于Z轴高度的智能楼层识别 #### 1.1 自动检测楼层高度 ```csharp private class FloorDetector { // 自动识别建筑中的楼层 public List DetectFloors(List allItems) { var floors = new List(); // 1. 收集所有楼板类构件 var slabs = allItems.Where(item => IsFloorSlab(item)).ToList(); // 2. 提取楼板顶面Z坐标 var slabZValues = slabs .Select(s => s.BoundingBox()?.Max.Z) .Where(z => z.HasValue) .Select(z => z.Value) .OrderBy(z => z) .ToList(); // 3. 聚类相近Z值,识别独立楼层 var floorLevels = ClusterZValues(slabZValues, tolerance: 0.5); // 4. 为每个楼层创建信息 for (int i = 0; i < floorLevels.Count; i++) { floors.Add(new FloorInfo { Index = i, BaseZ = floorLevels[i], Height = i < floorLevels.Count - 1 ? floorLevels[i + 1] - floorLevels[i] : 4.0, // 默认楼层高度 Name = $"第{i + 1}层" }); } return floors; } // 判断是否为楼板 private bool IsFloorSlab(ModelItem item) { var name = item.DisplayName?.ToLower() ?? ""; var className = item.ClassName?.ToLower() ?? ""; // 楼板关键词 string[] slabKeywords = { "floor", "楼板", "slab", "板", "deck", "地面", "楼面" }; if (slabKeywords.Any(k => name.Contains(k) || className.Contains(k))) { var bbox = item.BoundingBox(); if (bbox != null) { // 楼板特征:水平、薄 double thickness = bbox.Max.Z - bbox.Min.Z; double width = bbox.Max.X - bbox.Min.X; double length = bbox.Max.Y - bbox.Min.Y; // 厚度小,面积大 return thickness < 0.5 && width > 2.0 && length > 2.0; } } return false; } } ``` #### 1.2 快速楼层过滤 ```csharp private class FloorFilter { private List _floors; private int _targetFloorIndex; public FloorFilter(List floors, Point3D startPoint, Point3D endPoint) { _floors = floors; _targetFloorIndex = DetermineTargetFloor(startPoint, endPoint); } // 确定路径所在楼层 private int DetermineTargetFloor(Point3D startPoint, Point3D endPoint) { double avgZ = (startPoint.Z + endPoint.Z) / 2.0; // 找到最接近的楼层 for (int i = 0; i < _floors.Count; i++) { var floor = _floors[i]; if (avgZ >= floor.BaseZ && avgZ < floor.BaseZ + floor.Height) { return i; } } // 如果没找到,返回最接近的 return _floors .Select((f, i) => new { Index = i, Distance = Math.Abs(f.BaseZ - avgZ) }) .OrderBy(x => x.Distance) .First().Index; } // 快速判断模型项是否在目标楼层 public bool IsOnTargetFloor(ModelItem item) { var bbox = item.BoundingBox(); if (bbox == null) return false; var targetFloor = _floors[_targetFloorIndex]; double floorBottom = targetFloor.BaseZ - 0.5; // 容差 double floorTop = targetFloor.BaseZ + targetFloor.Height + 0.5; // 检查是否与楼层范围有交集 return bbox.Max.Z >= floorBottom && bbox.Min.Z <= floorTop; } // 批量过滤 public List FilterItems(List allItems) { return allItems.Where(IsOnTargetFloor).ToList(); } } ``` ### 方案2:分层空间哈希索引 #### 2.1 分层索引结构 ```csharp public class LayeredSpatialHashIndex { // 每个楼层有独立的空间哈希表 private Dictionary _floorHashTables; private List _floors; private double _hashCellSize; public LayeredSpatialHashIndex(double cellSize) { _hashCellSize = cellSize; _floorHashTables = new Dictionary(); } // 构建分层索引 public void BuildIndex(List items, List floors) { _floors = floors; // 为每个楼层创建独立的哈希表 foreach (var floor in floors) { _floorHashTables[floor.Index] = new SpatialHashTable(_hashCellSize); } // 将模型项分配到对应楼层 foreach (var item in items) { var bbox = item.BoundingBox(); if (bbox == null) continue; // 确定物体所属楼层(可能跨越多个楼层) var overlappingFloors = GetOverlappingFloors(bbox); foreach (var floorIndex in overlappingFloors) { _floorHashTables[floorIndex].Add(item, bbox); } } LogManager.Info($"[分层索引] 构建完成:{floors.Count}个楼层,{items.Count}个模型项"); } // 查询特定楼层的候选项 public IEnumerable QueryFloor(Point3D point, int floorIndex) { if (_floorHashTables.TryGetValue(floorIndex, out var hashTable)) { return hashTable.Query(point); } return Enumerable.Empty(); } // 获取物体跨越的楼层 private List GetOverlappingFloors(BoundingBox3D bbox) { var floors = new List(); for (int i = 0; i < _floors.Count; i++) { var floor = _floors[i]; double floorBottom = floor.BaseZ - 0.5; double floorTop = floor.BaseZ + floor.Height + 0.5; if (bbox.Max.Z >= floorBottom && bbox.Min.Z <= floorTop) { floors.Add(i); } } return floors; } } ``` #### 2.2 优化的垂直扫描 ```csharp public class FloorAwareVerticalScanner { private LayeredSpatialHashIndex _layeredIndex; private int _targetFloorIndex; private FloorInfo _targetFloor; // 限制扫描高度到单个楼层 public List ScanVerticalLine(Point3D basePoint) { // 只扫描目标楼层的高度范围 double scanMinZ = _targetFloor.BaseZ; double scanMaxZ = _targetFloor.BaseZ + _targetFloor.Height; // 只从目标楼层的空间哈希获取候选项 var candidates = _layeredIndex.QueryFloor(basePoint, _targetFloorIndex); // 高度筛选(范围已经大幅缩小) var filtered = candidates.Where(item => { var bbox = item.BoundingBox(); return bbox != null && bbox.Max.Z >= scanMinZ && bbox.Min.Z <= scanMaxZ; }); // 执行相交测试(候选项大幅减少) return PerformIntersectionTests(filtered, basePoint, scanMaxZ - scanMinZ); } } ``` ### 方案3:渐进式楼层过滤 #### 3.1 三级过滤策略 ```csharp public class ProgressiveFloorFilter { // 第一级:粗略高程过滤(构建索引前) public List CoarseFilter(List items, double targetZ) { const double coarseTolerance = 5.0; // 5米容差 return items.Where(item => { var bbox = item.BoundingBox(); if (bbox == null) return true; // 保留无边界框的项 // 快速排除明显不在目标楼层的项 return bbox.Max.Z >= targetZ - coarseTolerance && bbox.Min.Z <= targetZ + coarseTolerance; }).ToList(); } // 第二级:精确楼层过滤(空间哈希构建时) public List PreciseFilter(List items, FloorInfo targetFloor) { return items.Where(item => { var bbox = item.BoundingBox(); if (bbox == null) return false; double floorBottom = targetFloor.BaseZ - 0.2; double floorTop = targetFloor.BaseZ + targetFloor.Height + 0.2; return bbox.Max.Z >= floorBottom && bbox.Min.Z <= floorTop; }).ToList(); } // 第三级:垂直扫描时的高度限制 public bool ShouldProcess(ModelItem item, double scanZ, double floorHeight) { var bbox = item.BoundingBox(); if (bbox == null) return false; // 只处理与扫描高度相关的项 return bbox.Max.Z >= scanZ && bbox.Min.Z <= scanZ + floorHeight; } } ``` ## 性能分析 ### 不同场景的性能提升预期 | 建筑类型 | 楼层数 | 无过滤 | 简化过滤 | 精确过滤 | 分层索引 | |---------|--------|--------|---------|---------|---------| | 单层建筑 | 1 | 基准 | 无提升 | 无提升 | 无提升 | | 低层建筑 | 3-5 | 基准 | 1.5-2倍 | 3-4倍 | 4-5倍 | | 高层建筑 | 10-20 | 基准 | 2-3倍 | 10-15倍 | 15-20倍 | | 超高层 | 30+ | 基准 | 3-4倍 | 20-30倍 | 30-40倍 | ### 内存开销分析 - **基础过滤**:几乎无额外内存 - **精确过滤**:楼层信息缓存,约1KB/楼层 - **分层索引**:每层独立哈希表,约100KB/楼层 ## 实施建议 ### 第一阶段(立即可行) 1. 重新启用现有的`GetFloorFilteredModelItems`方法 2. 将高程容差从±10米优化到±2米 3. 添加楼层检测日志,收集实际使用数据 ### 第二阶段(短期优化) 1. 实现自动楼层检测 2. 基于Z轴的精确楼层过滤 3. 缓存楼层信息避免重复计算 ### 第三阶段(长期优化) 1. 实现分层空间哈希索引 2. 支持跨楼层路径规划 3. 优化楼梯/电梯节点处理 ## 风险与对策 ### 风险1:楼层识别错误 - **对策**:提供手动楼层选择界面 ### 风险2:跨楼层构件处理 - **对策**:将跨楼层构件添加到所有相关楼层 ### 风险3:非标准楼层高度 - **对策**:自适应楼层高度检测 ## 总结 楼层过滤是多层建筑路径规划的关键优化点。通过智能楼层识别和分层索引,可以实现10-40倍的性能提升。建议根据实际需求逐步实施,先验证简单方案的效果,再考虑复杂优化。