123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /*-------------------------------------------------------------------------
- * 功能描述: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.RevitUtils;
- using SAGA.RevitUtils.Data.Graph;
- using SAGA.RevitUtils.Extends;
- namespace SAGA.GplotRelationComputerManage
- {
- /// <summary>
- /// 拓扑图解析
- /// </summary>
- public class GplotGraphParse
- {
- public GplotGraphParse(GplotGraphSetting setting)
- {
- Setting = setting;
- }
- #region 属性相关
- /// <summary>
- /// 系统解析设置
- /// </summary>
- public GplotGraphSetting Setting { get; private set; }
- #endregion
- /// <summary>
- /// 创建拓扑结构图
- /// </summary>
- /// <param name="startElements"></param>
- /// <returns></returns>
- public List<SystemGraph> CreateGplotGraphs(List<Element> startElements)
- {
- List<SystemGraph> arrays = new List<SystemGraph>();
- var newStartElements = startElements.Distinct(new ElementEqualComparer()).ToList();
- while (newStartElements.Any())
- {
- var baseElement = newStartElements[0];
- var graph = CreateGplotGraph(baseElement);
- var containElements = graph.GetRefElements();
- newStartElements = newStartElements.Except(containElements, new ElementEqualComparer()).ToList();
- arrays.Add(graph);
- }
- return arrays;
- }
- /// <summary>
- /// 创建拓扑结构图
- /// </summary>
- /// <param name="element"></param>
- /// <returns></returns>
- public SystemGraph CreateGplotGraph(Element element)
- {
- SystemGraph graph = GetOriginGraph(element);
- //节点处理
- ArrangeVertex(graph);
- //边处理
- ArrangeEdge(graph);
- return graph;
- }
- #region 解析原始图
- /// <summary>
- /// 创建原始的节点图,以起点元素为首个节点
- /// </summary>
- /// <param name="element"></param>
- /// <returns></returns>
- public SystemGraph GetOriginGraph(Element element)
- {
- return SystemGraphUtil.CreateGraph(element, Setting.IgnoredConnector, Setting.BreakElement);
- }
- #endregion
- #region 相关子方法
- #region 节点处理
- /// <summary>
- /// 整理点
- /// </summary>
- /// <param name="graph"></param>
- private void ArrangeVertex(SystemGraph graph)
- {
- #region 分析
- /*
- * 1、如果节点元素是一个管道,则将管道没有连接的那一个点创建一个“空间”设备,标记不可合并
- * 2、如果节点是设备或者特殊阀门,则标记不能合并,并加载物理世界相关设备信息
- * 3、如果一个点只有两条边,且该点可以被合并,则创建新边,关联上述两条边和点信息;删除旧的信息
- * 4、如果一条边的两个点,都是可合并,并过滤所有以这两个点为顶点的边,将这些信息合并成新的点;
- * 处理这种点融合边的情况,有两种方案:1,创建新点,将旧的点设置为新点的子节点。2、修改所有边的相依的节点Id为新Id
- * 方案各有利弊,第一种保留了初始状态,第二种以后遍历时方便
- */
- #endregion
- AttachVertexInfo(graph);
- CombineVertex(graph);
- }
- /// <summary>
- /// 附加节点信息
- /// </summary>
- /// <param name="graph"></param>
- 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());
- }
- systemVertex.SetEquipment(item);
- break;
- }
- }
- }
- continue;
- }
- #endregion
- #region 真实设备处理
- item.Id = useElement.Id.ToString();
- item.BimId = useElement.GetBimId();
- if (MBIInfoUtil.IsEquipment(useElement))
- {
- systemVertex.CanCombine = false;
- systemVertex.SetEquipment(item);
- continue;
- }
- if (SystemCalcUtil.IsStartValve(useElement))
- {
- systemVertex.CanCombine = false;
- item.IsVirtual = true;
- systemVertex.SetEquipment(item);
- item.Name = useElement.GetFamily()?.Name;
- continue;
- }
- #endregion
- }
- #endregion
- }
- /// <summary>
- /// 合并节点
- /// </summary>
- /// <param name="graph"></param>
- 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))
- 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<Element> elements = new List<Element>();
- 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<string>() { 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.StartVertex = newVertex.Id;
- }
- else if (flag == 1)
- {
- systemEdge.EndVertex = newVertex.Id;
- }
- }
- }
- #endregion
- }
- #endregion
- }
- #endregion
- #region 边处理
- /// <summary>
- /// 整理边
- /// </summary>
- /// <param name="graph"></param>
- private void ArrangeEdge(SystemGraph graph)
- {
- //有向化处理
- DirectedEdge(graph);
- graph.IsDirection = true;
- //串并联处理
- EdgesArrayGraphUtil.GplotAnalyse(graph);
- }
- /// <summary>
- /// 确定流向
- /// </summary>
- /// <param name="graph"></param>
- 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 确定开始点
- List<string> edgeIds = new List<string>();
- List<string> vertexIds = new List<string>();
- Queue<SystemVertex> queueVertexes = new Queue<SystemVertex>();
- vertexes.ForEach(v => queueVertexes.Enqueue(v));
- bool isDeepSearch = false;
- bool isStart = true;
- while (queueVertexes.Any())
- {
- var currentVertex = queueVertexes.Dequeue();
- if (!isDeepSearch)
- {
- isStart = (currentVertex.GetEquipment()?.Name ?? string.Empty).Contains("入口");
- isDeepSearch = vertexes.LastOrDefault().Id == currentVertex.Id;
- }
- vertexIds.Add(currentVertex.Id);
- var edges = graph.GetInEdges(currentVertex.Id);
- foreach (var systemEdge in edges)
- {
- if (edgeIds.Contains(systemEdge.Id))
- {
- continue;
- }
- edgeIds.Add(systemEdge.Id);
- if ((isStart && systemEdge.ContainVertex(currentVertex.Id) == 1)||(!isStart&& 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)
- {
- queueVertexes.Enqueue(nextVertex);
- }
- }
- }
- }
- #endregion
- }
- #endregion
- #endregion
- }
- }
|