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