/*------------------------------------------------------------------------- * 功能描述:FloorSystemItems * 作者:xulisong * 创建时间: 2019/1/4 17:50:04 * 版本号:v1.0 * -------------------------------------------------------------------------*/ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Mechanical; using SAGA.DotNetUtils.Data; using SAGA.DotNetUtils.Extend; using SAGA.GplotRelationComputerManage.ColdRoom; using SAGA.Models; using SAGA.RevitUtils; using SAGA.RevitUtils.Extends; using SAGA.RevitUtils.MEP; namespace SAGA.GplotRelationComputerManage { public class FloorSystemItem { #region 构造函数 /// /// 初始化解析类 /// /// public FloorSystemItem(Document doc) { Document = doc; InitData(); } #endregion #region 属性相关 /// /// 关联模型信息 /// public Document Document { get; private set; } /// /// 使用关联标高 /// public Level UseLevel { get; private set; } private bool m_IsInited; /// /// 初始化数据 /// private void InitData() { if (m_IsInited) return; UseLevel = Document.GetUseView()?.GenLevel; m_IsInited = true; } #endregion #region 开始节点获取 /// /// 缓存信息 /// private List> m_StartNodes; /// /// 按系统获取开始节点 /// /// private List> GetStartNodes() { if (m_StartNodes != null) { //返回没有处理过的节点信息 return m_StartNodes.Where(s => !s.Handled).ToList(); } List> startNodes = new List>(); var doc = Document; #region 立管处理 /* * 暂时认定,一个立管之关联一个系统 */ var verticalPipes = doc.GetElements().Where(p => SystemCalcUtil.IsStart(p) && p.IsVerticalPipe()); foreach (var verticalPipe in verticalPipes) { ElementTreeNode node = new ElementTreeNode(); node.Current = verticalPipe; var systemTypeName = verticalPipe.GetSystemTypeName(); startNodes.Add(new StringFlag(systemTypeName, node)); } #endregion #region 特殊阀门处理 ElementCategoryFilter pipeFilter = new ElementCategoryFilter(BuiltInCategory.OST_PipeAccessory); ElementCategoryFilter ductFilter = new ElementCategoryFilter(BuiltInCategory.OST_DuctAccessory); ElementFilter filter = new LogicalOrFilter(pipeFilter, ductFilter); var specialValves = doc.FilterElements(filter).Where(f => SystemCalcUtil.IsStart(f)); foreach (var familyInstance in specialValves) { var connector = familyInstance.GetAllConnectors() .FirstOrDefault(c => Regex.IsMatch(c.Description, AppSetting.EndFlag)); if (connector == null) continue; var node = SystemParseManager.CreateTreeNode(familyInstance, connector, e => e is MEPCurve); var useMepCurve = node.GetLeaves().FirstOrDefault()?.Current as MEPCurve; if (useMepCurve == null) continue; var systemTypeName = useMepCurve.GetSystemTypeName(); startNodes.Add(new StringFlag(systemTypeName, node)); } #endregion return m_StartNodes = startNodes; } #endregion #region 设备节点获取 /// /// 模型中包含的设备 /// public Dictionary> RevitEquipments { get; private set; } /// /// 通过设备类型获取相关设备 /// /// private List GetEquipments(string category) { if (RevitEquipments == null) { var doc = Document; var fies = doc.FilterElements(); List> original = new List>(); foreach (var familyInstance in fies) { var familyName = familyInstance.GetFamily().Name; if (string.IsNullOrEmpty(familyName)) continue; var match = Regex.Match(familyName, @"^(?:((?:[A-Z][A-Z]){2,3})\s*-\s*\S*)"); if (match.Success) { original.Add(new StringFlag(match.Groups[1].ToString(), familyInstance)); } } RevitEquipments = original.GroupBy(f => f.Flag) .ToDictionary(g => g.Key, g => g.ToList().Select(f => f.Instance).ToList()); } RevitEquipments.TryGetValue(category, out List result); return result ?? new List(); } #endregion #region 数据解析方法 /// /// 解析当前楼层系统数据 /// /// public void Parse(SystemComputerContext context) { if (UseLevel == null) return; var doc = Document; var relations = context.Relations; foreach (var relation in relations) { var shell = context.RelationShells.GetItem(relation); if (shell.IsPipeSystem()) { ParsePipe(context, shell,Domain.DomainPiping); } else { ParseDuct(context, shell); } } } #region 水系统解析 public void ParsePipe(SystemComputerContext context, RelationTypeShell relationSetting, Domain currentDomain) { Domain useDomain = currentDomain;//Domain.DomainPiping; var relationType = relationSetting.RelationItem.Type; List drawRecords = new List(); List relationRecords = new List(); List roomStartElements = new List(); #region 计算拓扑树形结构 /* * 1、遍历开始点的限制:特殊阀门,指定标注的Connector;立管,已连接连接件;空间,相交风管元素; * 2、根据拓扑图关联的对象信息,找到系统关联的设备生成节点。如果没有遍历到要独立生成 * 3、要不要显示端头管所在空间的位置 */ var startNodes = GetStartNodes(); List useIds = new List(); List verticalMepCurves = new List(); for (int i = 0; i < startNodes.Count; i++) { var startNode = startNodes[i]; var useRelation = relationSetting.GetFirstMatchSystem(startNode.Flag); if (useRelation == null) continue; //加入开始元素 if (startNode.Instance.Current is FamilyInstance) { roomStartElements.Add(startNode.Instance.Current); } if (useIds.Any(id => id == startNode.Instance.Current.Id.IntegerValue)) { continue; } //加入立管 if (startNode.Instance.Current is MEPCurve mepCurve) { verticalMepCurves.Add(mepCurve); } var tempIds = SystemParseManager.BuildSystemNode(startNode.Instance, useDomain, (m => !startNode.Flag.Equals(m.GetSystemTypeName()))); if (tempIds.Any(d => d == 534844|| d == 534845)) { } startNode.Instance.PipeSystemTypeName = startNode.Flag; BuildElementNodeData(context, startNode.Instance); useIds.AddRange(tempIds); startNode.Handled = true; //可以清空Leaves的子节点 #region 整理原始数据 //判断是否有设备节点,不进行数据处理 var useNode = startNode.Instance; //var firstEquipment = useNode.FirstOrDefault(t => MBIInfoUtil.IsEquipment(t.Current)); //要不要以这个为判定条件,图形可以画出,关系肯定是没有的 //if (firstEquipment != null) if (useNode.Nodes.Any()) { //存在设备则保存信息 var drawRecord = BuildFloorDrawRecord(relationSetting, useNode); drawRecord.SystemName = startNode.Flag; drawRecords.Add(drawRecord); var relationRecord = BuildFloorRelationRecord(relationSetting, useNode,context); relationRecords.Add(relationRecord); } #endregion } #region 解析机房数据 var useEquipments = ParseMachineRoomData(context, relationSetting, roomStartElements); useEquipments = useEquipments.Distinct().ToList(); #endregion //获取没有使用过的对象节点 List singleInstances = relationSetting.RelationItem.Objects.SelectMany(o => GetEquipments(o.Type)).ToList(); for (int i = 0; i < singleInstances.Count; i++) { var useInstance = singleInstances[i]; if (useIds.Any(id => id == useInstance.Id.IntegerValue) || useEquipments.Any(id => id == useInstance.Id.ToString())) { continue; } var connectors = useInstance.GetAllConnectors(); foreach (var connector in connectors) { if (connector.Domain != useDomain) { continue; } var startNode = SystemParseManager.CreateTreeNode(useInstance, connector, e => e is MEPCurve); //查找需要遍历的路径信息 var leaves = startNode.GetLeaves(); //使用过的系统不再进行遍历 List useSystems = new List(); foreach (var leaf in leaves) { var useMepCurve = leaf?.Current as MEPCurve; if (useMepCurve == null) continue; var systemTypeName = useMepCurve.GetSystemTypeName(); if (!relationSetting.IsMatchSystem(systemTypeName)) { continue; } if (useSystems.Any(s => s == systemTypeName)) { continue; } useSystems.Add(systemTypeName); //创建制定的startNode;[一个分支,一个分支去处理] ElementTreeNode newStartNode = new ElementTreeNode() {Current = useInstance}; var tempIds = SystemParseManager.BuildSystemNode(newStartNode, useDomain, (m => !systemTypeName.Equals(m.GetSystemTypeName()))); newStartNode.PipeSystemTypeName = systemTypeName; BuildElementNodeData(context, newStartNode); useIds.AddRange(tempIds); #region 生成绘图,计算数据 //解析数据,找管道定系统,管道找不到,系统名为"关联类型-未知" var drawRecord = BuildFloorDrawRecord(relationSetting, newStartNode); drawRecord.SystemName = systemTypeName; drawRecords.Add(drawRecord); var relationRecord = BuildFloorRelationRecord(relationSetting, newStartNode, context); relationRecords.Add(relationRecord); #endregion } } } #endregion //增加立管数据 ComputerVerticalPipes(UseLevel, verticalMepCurves, context, relationSetting); context[relationType].FloorDrawRecords.AddRange(drawRecords); context[relationType].FloorRelationRecords.AddRange(relationRecords); } #endregion #region 风系统解析 public void ParseDuct(SystemComputerContext context, RelationTypeShell relationSetting) { ParsePipe(context, relationSetting, Domain.DomainHvac); } #endregion #endregion #region 解析立管 /* * 1、解析立管需要考虑,竖直风管,水管,空间的情况; *2、将各层数据汇总,才能统一计算立管的相关关系数据 */ private void ComputerVerticalPipes(Level refLevel, List mepCurves, SystemComputerContext context, RelationTypeShell relationSetting) { var result = new List(); var spaces = Document.GetElements(BuiltInCategory.OST_MEPSpaces).OfType(); var level = refLevel; var relationType = relationSetting.RelationItem.Type; var currentLevelName = MBIInfoUtil.GetFloorNameByLevel(level.Name); foreach (var pipe in mepCurves) { if (pipe == null) continue; var vp = new VerticalPipe { Id = pipe.Id.IntegerValue.ToString(), LevelName = currentLevelName, LevelElevation = level.Elevation, UpPoint3D = PointConverter.XYZToPoint3D(pipe.GetVerticalTopPoint()), DownPoint3D = PointConverter.XYZToPoint3D(pipe.GetVerticalBottomPoint()), PipeSytemType = pipe.GetSystemTypeName() }; #region 获取立管关联空间 var locationCurve = pipe.GetLocationCurve(); var midPoint = (locationCurve.StartPoint() + locationCurve.EndPoint()) / 2; Space refSpace = spaces.FirstOrDefault(s => s.IsPointInSpace(midPoint)); //关联 var display = context.GetSpaceDisplay(refSpace, out string tip); vp.Display = $"{display}:{pipe.Id.IntegerValue.ToString()}"; vp.DisplayTip = tip ?? string.Empty; #endregion result.Add(vp); } LevelData levelData = new LevelData() { Id = refLevel.Id.ToString(), Name = MBIInfoUtil.GetFloorNameByLevel(refLevel.Name) }; context[relationType].VerticalPipes.AddRange(result); context[relationType].Levels.Add(levelData); } #endregion #region 保存数据类对象创建 private string GetUnknownSystemName(RelationTypeShell relationShell) { return relationShell.RelationItem?.Name + "---未知"; } private FloorDrawRecord BuildFloorDrawRecord(RelationTypeShell relationShell, ElementTreeNode node) { var floorDraw = new FloorDrawRecord(); floorDraw.SetFloorLevel(UseLevel); floorDraw.RelationType = relationShell.RelationItem.Type; floorDraw.DrawIems = SystemParseManager.CreateDrawing(node) ?? new SystemDrawItems(); return floorDraw; } private FloorRelationRecord BuildFloorRelationRecord(RelationTypeShell relationShell, ElementTreeNode node, SystemComputerContext context) { var floorRelation = new FloorRelationRecord(); floorRelation.SetFloorLevel(UseLevel); floorRelation.RelationType = relationShell.RelationItem.Type; var records= SystemParseManager.CreateRelation(node) ?? new List(); floorRelation.RelationItems = records; var mathSystem=relationShell.GetFirstMatchSystem(node.PipeSystemTypeName); var edgeType = mathSystem.ContainEdgeTypes.FirstOrDefault(); if(string.IsNullOrWhiteSpace(edgeType)) { edgeType = "1"; } //增加关联对象名称 records.ForEach(e => { var nodes = new List() { e.From, e.To }; nodes.ForEach(n => n.MbiId = context.EquipmentItems.GetItem(n.BimId)?.Id); e.RelationType = edgeType; if(mathSystem!=null&&mathSystem.FlowType==FlowType.Out) { //根据流向反转关系 e.Reverse(); } }); return floorRelation; } #endregion #region 初始化名称,分类 /// /// 初始化节点扩展数据 /// /// /// private void BuildElementNodeData(SystemComputerContext context, ElementTreeNode node) { Queue nodeQueue = new Queue(); nodeQueue.Enqueue(node); while (nodeQueue.Any()) { #region 控制验证 var currentNode = nodeQueue.Dequeue(); if (currentNode == null) continue; var element = currentNode.Current; if (element == null) continue; #endregion if (element is FamilyInstance fiEq) { #region 判断是否是设备 if (MBIInfoUtil.IsEquipment(fiEq)) { var equipItem = context.EquipmentItems.GetItem(fiEq.GetBimId()); NodeExtendData data = new NodeExtendData(); if (equipItem != null) { data.Name = equipItem.GetDisplay(); data.Category = equipItem.Category; } else { data.Name = fiEq.GetFamily()?.Name; } data.SystemType = node.PipeSystemTypeName; currentNode.Tag = data; } #endregion } else if (element is Space revitSpace) { var space = context.Rooms.GetItem(element.GetBimId()); NodeExtendData data = new NodeExtendData(); if (space != null) { data.Name = space.GetDisplay(); } else { data.Name = revitSpace.Name; } data.SystemType = node.PipeSystemTypeName; currentNode.Tag = data; } currentNode.Nodes.ForEach(e => nodeQueue.Enqueue(e)); } } #endregion #region 解析机房数据 /// /// 解析机房数据 /// /// /// /// private List ParseMachineRoomData(SystemComputerContext context, RelationTypeShell relationSetting, List startElements) { /* *1、解析过程中尽量少处理和后续相关的数据 * 2、设备整理,带缓存的设备信息读取 */ List useEquipments = new List(); var relationType = relationSetting.RelationItem.Type; SystemParse parse = new SystemParse(new SystemParseSetting(relationSetting)); List useStartElements = new List(startElements); var arrays = parse.Execute(useStartElements); arrays.RemoveAll(c => c.GetAvailableVertexes(null).All(v => !v.IsRealEquipment())); #region 生成图形数据 ColdRoomManager manager = new ColdRoomManager(); var doc = manager.CreateDocument(new List(arrays)); var drawData = SystemParseManager.CreateRoomDrawing(doc); MachineRoomDrawRecord record = new MachineRoomDrawRecord(); record.RelationName = relationSetting.RelationItem.Name; record.FloorName = MBIInfoUtil.GetFloorNameByLevel(UseLevel.Name); record.DrawIems = drawData; context[relationType].MachineRoomDrawRecords.Add(record); #endregion #region 生成关系数据 var relations = manager.CreateRelation(arrays); MachineRoomRelationRecord relationRecord = new MachineRoomRelationRecord(); relationRecord.RelationName = relationSetting.RelationItem.Name; foreach (var item in relations) { var node = new BinaryRelationItem(); node.From = ConverEquipmentNode(item.EquipmentItem1, context); node.To = ConverEquipmentNode(item.EquipmentItem2, context); node.RelationType = item.LinkType; relationRecord.RelationItems.Add(node); var newIds = new List() {item.EquipmentItem1.Id, item.EquipmentItem2.Id}; useEquipments.AddRange(newIds); } context[relationType].MachineRoomRelationRecords.Add(relationRecord); #endregion return useEquipments; } private EquipmentNode ConverEquipmentNode(EquipmentItem item, SystemComputerContext context) { EquipmentNode result = new EquipmentNode(); result.IsRealEquipment = !item.IsVirtual; result.RevitId = item.Id; result.BimId = CreateBimId(result.RevitId); var equipment = context.EquipmentItems.GetItem(result.BimId); if (equipment != null) { result.MbiId = equipment.Id ?? string.Empty; result.Category = equipment.Category; } else { result.Category = MBIInfoUtil.GetEquipmentCategory(item.Name) ?? string.Empty; } return result; } #endregion 解析机房数据 /// /// 根据revitId获取bimId /// /// /// private string CreateBimId(string revitId) { return string.Format($"{Document.PathName.GetFileName()}:{revitId}"); } } }