/*-------------------------------------------------------------------------
* 功能描述: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
}
}