/*------------------------------------------------------------------------- * 功能描述:GplotGraphParse * 作者:xulisong * 创建时间: 2019/2/14 17:51:58 * 版本号:v1.0 * -------------------------------------------------------------------------*/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autodesk.Revit.DB; using SAGA.DotNetUtils.Data; using SAGA.DotNetUtils.Extend; using SAGA.GplotRelationComputerManage.SystemChecks; using SAGA.RevitUtils; using SAGA.RevitUtils.Data.Graph; using SAGA.RevitUtils.Extends; namespace SAGA.GplotRelationComputerManage { /// /// 拓扑图解析 /// public class GplotGraphParse { public GplotGraphParse(GplotGraphSetting setting) { Setting = setting; } #region 属性相关 /// /// 系统解析设置 /// public GplotGraphSetting Setting { get; private set; } #endregion #region 创建拓扑图信息 /// /// 创建拓扑结构图 /// /// /// public List CreateGplotGraphs(List startElements) { List arrays = new List(); var newStartElements = startElements.Distinct(new ElementEqualComparer()).ToList(); while (newStartElements.Any()) { var baseElement = newStartElements[0]; newStartElements.Remove(baseElement); var graph = CreateGplotGraph(baseElement); var containElements = graph.GetRefElements(); newStartElements = newStartElements.Except(containElements, new ElementEqualComparer()).ToList(); arrays.Add(graph); } return arrays; } /// /// 创建拓扑结构图 /// /// /// public SystemGraph CreateGplotGraph(Element element) { SystemGraph graph = GetOriginGraph(element); //节点处理 ArrangeVertex(graph); //边处理 ArrangeEdge(graph); return graph; } #endregion #region 解析原始图 /// /// 创建原始的节点图,以起点元素为首个节点 /// /// /// public SystemGraph GetOriginGraph(Element element) { return SystemGraphUtil.CreateGraph(element, Setting.IgnoredConnector, Setting.IgnoredElement,Setting.BreakElement); } #endregion #region 相关子方法 #region 节点处理 /// /// 整理点 /// /// private void ArrangeVertex(SystemGraph graph) { #region 分析 /* * 1、如果节点元素是一个管道,则将管道没有连接的那一个点创建一个“空间”设备,标记不可合并 * 2、如果节点是设备或者特殊阀门,则标记不能合并,并加载物理世界相关设备信息 * 3、如果一个点只有两条边,且该点可以被合并,则创建新边,关联上述两条边和点信息;删除旧的信息 * 4、如果一条边的两个点,都是可合并,并过滤所有以这两个点为顶点的边,将这些信息合并成新的点; * 处理这种点融合边的情况,有两种方案:1,创建新点,将旧的点设置为新点的子节点。2、修改所有边的相依的节点Id为新Id * 方案各有利弊,第一种保留了初始状态,第二种以后遍历时方便 */ #endregion AttachVertexInfo(graph); var newCount = graph.GetBootVertexs().Count; var oldCount = 0; do { oldCount = newCount; CombineVertex(graph); newCount = graph.GetBootVertexs().Count; //数量不变,算处理完 } while (oldCount != newCount); } /// /// 附加节点信息 /// /// private void AttachVertexInfo(SystemGraph graph) { var useVertexes = graph.GetBootVertexs(); #region foreach (var systemVertex in useVertexes) { var data = systemVertex.Data; if (!data.Any()) { continue; } //理论上此时场景,有且仅有一个关联元素 var useElement = data[0]; #region 虚拟设备处理 EquipmentItem item = new EquipmentItem(); if (useElement is MEPCurve) { item.IsVirtual = true; var edges = graph.GetOutEdges(systemVertex.Id); if (edges.Count == 1) { var currentEdge = edges[0]; var joinItems = JoinItem.GetJoinItems(useElement); foreach (var joinItem in joinItems) { if (joinItem.RefElement != null && currentEdge.Data.All(e => e.Id != joinItem.RefElement.Id)) { //处理点边关联信息 currentEdge.Data.Add(useElement); systemVertex.Data.Remove(useElement); systemVertex.CanCombine = false; //找到断头点 var location = joinItem.RefConnector.Origin; var space = useElement.Document.GetSpaceAtPoint(location); if (space != null) { item.Id = space.Id.ToString(); item.BimId = space.GetBimId(); } else { item.Name = string.Format("空间{0}", location.ToString()); } item.ElementType = SystemCalcUtil.IsStart(useElement)?ElementType.VerticalPipe: ElementType.Space; if (SystemCalcUtil.IsStart(useElement)) { item.Name = string.Format("【{0}】立管:{1}", (useElement as MEPCurve).GetSystemTypeName(),useElement.Id.ToString()); } systemVertex.SetEquipment(item); break; } } } continue; } #endregion #region 真实设备处理 item.Id = useElement.Id.ToString(); item.BimId = useElement.GetBimId(); item.Name = useElement.GetFamily()?.Name; if (MBIInfoUtil.IsEquipment(useElement)) { systemVertex.CanCombine = false; item.ElementType = ElementType.Equipment; systemVertex.SetEquipment(item); continue; } if (SystemCalcUtil.IsStartValve(useElement)) { systemVertex.CanCombine = false; item.IsVirtual = true; item.ElementType = ElementType.Equipment; systemVertex.SetEquipment(item); continue; } #endregion } #endregion } /// /// 合并节点 /// /// public void CombineVertex(SystemGraph graph) { #region 以点为基础处理 var useVertexes = graph.GetBootVertexs(); foreach (var systemVertex in useVertexes) { if (!systemVertex.CanCombine) { continue; } var edges = graph.GetInEdges(systemVertex.Id); if (edges.Count != 2) { continue; } string startId = edges[0].GetAnotherVertex(systemVertex.Id); string endId = edges[1].GetAnotherVertex(systemVertex.Id); edges.ForEach(e => graph.RemoveEdge(e.Id)); graph.RemoveVertex(systemVertex.Id); var newEdge = new SystemEdge(startId, endId); newEdge.Data = new SystemData(edges[0].Data); newEdge.Data.ExtendRefElements(edges[1].Data); newEdge.Data.ExtendRefElements(systemVertex.Data); graph.AddEdge(newEdge); } #endregion #region 以边为基础处理 HandledMap map = new HandledMap(); var useEdges = graph.GetBootEdges(); for (int i = 0; i < useEdges.Count; i++) { var baseEdge = useEdges[i]; if (map.GetHandled(baseEdge.Id)) continue; var startVertex = graph.GetBootStartVertex(baseEdge); var endVertex = graph.GetBootEndVertex(baseEdge); if (startVertex == null || endVertex == null) { continue; } if (!startVertex.CanCombine || !endVertex.CanCombine) { continue; } // 如果两个节点之下还有一条其他的包含设备的边,则该边的两点不能合并 var refEdges = graph.GetEdges(baseEdge.StartVertex, baseEdge.EndVertex); #region 创建新的点 List elements = new List(); elements.AddRange(startVertex.Data); elements.AddRange(endVertex.Data); foreach (var elementsEdge in refEdges) { elements.AddRange(elementsEdge.Data); graph.RemoveEdge(elementsEdge.Id); map.SetHandled(elementsEdge.Id, true); } graph.RemoveVertex(startVertex.Id); graph.RemoveVertex(endVertex.Id); elements = elements.Distinct(new ElementEqualComparer()).ToList(); SystemVertex newVertex = new SystemVertex(new SystemData(elements)); newVertex = graph.AddVertex(newVertex); #endregion #region 更新关联边的关联点 var vertexIds = new List() { startVertex.Id, endVertex.Id }; foreach (var vertexId in vertexIds) { var edges = graph.GetInEdges(vertexId); foreach (var systemEdge in edges) { var flag = systemEdge.ContainVertex(vertexId); if (flag == 0) { systemEdge.UpdateStartVertex(newVertex.Id); } else if (flag == 1) { systemEdge.UpdateEndVertex(newVertex.Id); } } } #endregion } #endregion } #endregion #region 边处理 /// /// 整理边 /// /// private void ArrangeEdge(SystemGraph graph) { //有向化处理 DirectedEdge(graph); //DirectedEdge2(graph); graph.IsDirection = true; //串并联处理 //EdgesArrayGraphUtil.GplotAnalyse(graph); } /// /// 确定流向 /// /// private void DirectedEdge(SystemGraph graph) { #region 加载边的系统信息 var originEdges = graph.Edges.Where(e => !e.Children.Any()).ToList(); foreach (var originEdge in originEdges) { var refElements = originEdge.Data; //获取边系统类型 originEdge.SystemName = (refElements.FirstOrDefault(e => e is MEPCurve) as MEPCurve)?.GetSystemTypeName(); //根据系统类型和特殊设备确定旁通和补水;未完,待续 var systemItem = Setting.RelationTypeShell.GetFirstMatchSystem(originEdge.SystemName); if (systemItem != null) { originEdge.EdgeCategory = systemItem.ContainEdgeTypes.FirstOrDefault(); originEdge.FlowType = systemItem.FlowType == FlowType.In ? 2 : 1; } } #endregion #region 描述 /* * 1、查找遍历起点 * 2、根据起点遍历所有的节点,并调整节点的顺序 */ #endregion #region 获取定义端点 var vertexes = graph.GetBootVertexs().Where(v => SystemCalcUtil.IsStartValveName(v.GetEquipment()?.Name)).ToList(); if (!vertexes.Any()) return; foreach (var systemVertex in vertexes) { var tempEdges = graph.GetInEdges(systemVertex.Id); if (tempEdges.Any()) { var item = systemVertex.GetEquipment(); if (item == null) { continue; } if (tempEdges.Any(e => e.FlowType == 2)) { item.Name = "出口" + item.Id; } else { item.Name = "入口" + item.Id; } } } #endregion #region 确定开始点 HashSet edgeIds = new HashSet(); //点遍历id区分系 flowType信息 HashSet vertexIds = new HashSet(); foreach (var systemVertex in vertexes) { if (vertexIds.Contains(systemVertex.Id)) { continue; } bool isStart = true; var currentVertexName = systemVertex.GetEquipment().Name; if (string.IsNullOrWhiteSpace(currentVertexName)) { continue; } var useFlowType = 0; if (currentVertexName.Contains("入口")) { useFlowType = 1; isStart = true; } else if(currentVertexName.Contains("出口")) { useFlowType = 2; isStart = false; } else { continue; } Queue queueVertexes = new Queue(); queueVertexes.Enqueue(systemVertex); Func commonId = (str) => useFlowType + "_" + str ; while (queueVertexes.Any()) { var currentVertex = queueVertexes.Dequeue(); //普通节点Id if (vertexIds.Contains(commonId(currentVertex.Id))) { continue; } vertexIds.Add(commonId(currentVertex.Id)); var edges = graph.GetInEdges(currentVertex.Id); foreach (var systemEdge in edges) { if (systemEdge.FlowType != useFlowType) { continue; } if (edgeIds.Contains(systemEdge.Id)) { continue; } var otherId = systemEdge.GetAnotherVertex(currentVertex.Id); if (vertexes.Any(v => v.Id == otherId)) { continue; } edgeIds.Add(systemEdge.Id); if ((isStart && systemEdge.ContainVertex(currentVertex.Id) == 1) || (!isStart && systemEdge.ContainVertex(currentVertex.Id) == 0)) { systemEdge.Reverse(); } if (!vertexIds.Contains(commonId(otherId))) { var nextVertex = graph.FindVertex(otherId); if (nextVertex != null) { queueVertexes.Enqueue(nextVertex); } } } } } #endregion } /// /// 确定流向, /// /// private void DirectedEdge2(SystemGraph graph) { #region 加载边的系统信息 var originEdges = graph.Edges.Where(e => !e.Children.Any()).ToList(); foreach (var originEdge in originEdges) { var refElements = originEdge.Data; //获取边系统类型 originEdge.SystemName = (refElements.FirstOrDefault(e => e is MEPCurve) as MEPCurve)?.GetSystemTypeName(); //根据系统类型和特殊设备确定旁通和补水;未完,待续 var systemItem = Setting.RelationTypeShell.GetFirstMatchSystem(originEdge.SystemName); if (systemItem != null) { originEdge.EdgeCategory = systemItem.ContainEdgeTypes.FirstOrDefault(); originEdge.FlowType = systemItem.FlowType == FlowType.In ? 2 : 1; } } #endregion #region 描述 /* * 1、查找遍历起点 * 2、根据起点遍历所有的节点,并调整节点的顺序 */ #endregion #region 获取定义端点 Document refDocument = null; foreach (var vertex in graph.Vertexes) { if (vertex.Data == null) continue; refDocument = vertex.Data.FirstOrDefault()?.Document; if (refDocument != null) break; } if (refDocument == null) return; //获取开始的category //如果没有设定开始点,则使用立管作为开始点 List vertexes = new List(); List startCategories = GplotSystemCheckManager.GetSourceCategories(refDocument,Setting.RelationTypeShell.RelationItem.Type); if (startCategories.Any()) { vertexes = graph.GetBootVertexs().Where(v => startCategories.Contains(MBIInfoUtil.GetEquipmentCategory(v.GetEquipment()?.Name) ?? string.Empty)).ToList(); } else { vertexes = graph.GetBootVertexs().Where(v => v.GetEquipment()!=null&&v.GetEquipment().ElementType==ElementType.VerticalPipe).ToList(); } if (!vertexes.Any()) return; #endregion #region 确定开始点 List edgeIds = new List(); List vertexIds = new List(); for (int i = 0; i < vertexes.Count; i++) { var currentVertex = vertexes[i]; if (vertexIds.Contains(currentVertex.Id)) { continue; } vertexIds.Add(currentVertex.Id); var edges = graph.GetInEdges(currentVertex.Id); foreach (var systemEdge in edges) { if (systemEdge.FlowType > 2) { continue; } if (edgeIds.Contains(systemEdge.Id)) { continue; } edgeIds.Add(systemEdge.Id); if ((systemEdge.FlowType==2&&systemEdge.ContainVertex(currentVertex.Id) == 1)|| (systemEdge.FlowType == 1 && systemEdge.ContainVertex(currentVertex.Id) == 0)) { systemEdge.Reverse(); } var otherId = systemEdge.GetAnotherVertex(currentVertex.Id); if (!vertexIds.Contains(otherId)) { var nextVertex = graph.FindVertex(otherId); if (nextVertex != null) { vertexes.Add(nextVertex); } } } } #endregion } #region 无向拓扑展开 private class VertexInfo { public VertexInfo() { } public VertexInfo(List edges) { AllEdges = edges; CurrentDegree = edges.Count; } /// /// 关联边 /// public List AllEdges { get; set; } = new List(); public int CurrentDegree { get; set; } } /// /// 确定流向 /// /// private void DirectedEdge3(SystemGraph graph) { #region 加载边的系统信息 var originEdges = graph.Edges.Where(e => !e.Children.Any()).ToList(); foreach (var originEdge in originEdges) { var refElements = originEdge.Data; //获取边系统类型 originEdge.SystemName = (refElements.FirstOrDefault(e => e is MEPCurve) as MEPCurve)?.GetSystemTypeName(); //根据系统类型和特殊设备确定旁通和补水;未完,待续 var systemItem = Setting.RelationTypeShell.GetFirstMatchSystem(originEdge.SystemName); if (systemItem != null) { originEdge.EdgeCategory = systemItem.ContainEdgeTypes.FirstOrDefault(); originEdge.FlowType = systemItem.FlowType == FlowType.In ? 2 : 1; } } #endregion #region 描述 /* * 1、查找遍历起点 * 2、根据起点遍历所有的节点,并调整节点的顺序 */ #endregion var allVertexs = graph.GetBootVertexs(); #region 获取定义端点 var vertexes = allVertexs.Where(v => SystemCalcUtil.IsStartValveName(v.GetEquipment()?.Name)).ToList(); if (!vertexes.Any()) return; //将顶点按前缀分组 Dictionary> dicVertexes = new Dictionary>(); foreach (var systemVertex in vertexes) { var tempEdges = graph.GetInEdges(systemVertex.Id); if (tempEdges.Any()) { var item = systemVertex.GetEquipment(); if (item == null) { continue; } if (tempEdges.Any(e => e.FlowType == 2)) { item.Name = "出口" + item.Id; dicVertexes.AddGroupValue("出口", systemVertex); } else { item.Name = "入口" + item.Id; dicVertexes.AddGroupValue("出口", systemVertex); } } } #endregion #region 这里所有点的边集合信息和度的信息 Dictionary vertexInfos = new Dictionary(); foreach (var systemVertex in allVertexs) { var edges = graph.GetInEdges(systemVertex.Id); vertexInfos[systemVertex.Id] = new VertexInfo(edges); } #endregion #region 确定开始点 HashSet edgeIds = new HashSet(); //点遍历id区分系 flowType信息 HashSet vertexIds = new HashSet(); foreach (var dicVertex in dicVertexes) { #region 确定初始状态 bool isStart = true; var useFlowType = 0; var key = dicVertex.Key; if (key.Contains("入口")) { useFlowType = 1; isStart = true; } else if (key.Contains("出口")) { useFlowType = 2; isStart = false; } else { continue; } #endregion Func commonId = (str) => useFlowType + "_" + str; var useVertexes = new List(dicVertex.Value); useVertexes.ForEach(v => vertexInfos[v.Id].CurrentDegree = -1); while (useVertexes.Count > 0) { var useVertex = useVertexes[0]; var useId = useVertex.Id; useVertexes.RemoveAt(0); if (vertexIds.Contains(useId)) { continue; } vertexIds.Add(commonId(useId)); var vertexInfo = vertexInfos[useId]; var currentVextexCount = useVertexes.Count; foreach (var systemEdge in vertexInfo.AllEdges) { if (systemEdge.FlowType != useFlowType) { continue; } if (edgeIds.Contains(systemEdge.Id)) { continue; } var otherId = systemEdge.GetAnotherVertex(useId); if (vertexes.Any(v => v.Id == otherId)) { continue; } edgeIds.Add(systemEdge.Id); if ((isStart && systemEdge.ContainVertex(useId) == 1) || (!isStart && systemEdge.ContainVertex(useId) == 0)) { systemEdge.Reverse(); } if (!vertexIds.Contains(commonId(otherId))) { var nextVertex = graph.FindVertex(otherId); if (nextVertex != null) { useVertexes.Add(nextVertex); } } var otherInfo = vertexInfos[otherId]; otherInfo.CurrentDegree = otherInfo.CurrentDegree - 1; } var newVextexCount = useVertexes.Count; if (currentVextexCount != newVextexCount) { useVertexes = useVertexes.OrderBy(v => vertexInfos[v.Id].CurrentDegree).ToList(); } } } #endregion } #endregion #endregion #endregion } }