|
@@ -10,10 +10,377 @@ using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
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
|
|
namespace SAGA.GplotRelationComputerManage
|
|
{
|
|
{
|
|
- class GplotGraphParse
|
|
|
|
|
|
+ /// <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
|
|
}
|
|
}
|
|
}
|
|
}
|