123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 |
- /*-------------------------------------------------------------------------
- * 功能描述:FloorSystemItems
- * 作者:xulisong
- * 创建时间: 2019/1/4 17:50:04
- * 版本号:v1.0
- * -------------------------------------------------------------------------*/
- using System;
- 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.Models;
- using SAGA.RevitUtils;
- using SAGA.RevitUtils.Extends;
- using SAGA.RevitUtils.MEP;
- namespace SAGA.GplotRelationComputerManage
- {
- public class FloorSystemItem
- {
- #region 构造函数
- /// <summary>
- /// 初始化解析类
- /// </summary>
- /// <param name="doc"></param>
- public FloorSystemItem(Document doc)
- {
- Document = doc;
- InitData();
- }
- #endregion
- #region 属性相关
- /// <summary>
- /// 关联模型信息
- /// </summary>
- public Document Document { get; private set; }
- /// <summary>
- /// 使用关联标高
- /// </summary>
- public Level UseLevel { get; private set; }
- private bool m_IsInited;
- /// <summary>
- /// 初始化数据
- /// </summary>
- private void InitData()
- {
- if (m_IsInited)
- return;
- UseLevel = Document.GetUseView()?.GenLevel;
- m_IsInited = true;
- }
- #endregion
- #region 开始节点获取
- /// <summary>
- /// 缓存信息
- /// </summary>
- private List<StringFlag<ElementTreeNode>> m_StartNodes;
- /// <summary>
- /// 按系统获取开始节点
- /// </summary>
- /// <returns></returns>
- private List<StringFlag<ElementTreeNode>> GetStartNodes()
- {
- if (m_StartNodes != null)
- {
- //返回没有处理过的节点信息
- return m_StartNodes.Where(s => !s.Handled).ToList();
- }
- List<StringFlag<ElementTreeNode>> startNodes = new List<StringFlag<ElementTreeNode>>();
- var doc = Document;
- #region 立管处理
- /*
- * 暂时认定,一个立管之关联一个系统
- */
- var verticalPipes = doc.GetElements<MEPCurve>().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<ElementTreeNode>(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<ElementTreeNode>(systemTypeName, node));
- }
- #endregion
- return m_StartNodes = startNodes;
- }
- private List<StringFlag<Element>> m_RoomStartElements;
- /// <summary>
- /// 获取机房开始元素
- /// </summary>
- /// <param name="relationSetting"></param>
- /// <returns></returns>
- private List<Element> GetRoomStartNodes(RelationTypeShell relationSetting)
- {
- if (m_RoomStartElements == null)
- {
- m_RoomStartElements = new List<StringFlag<Element>>();
- ElementCategoryFilter pipeFilter = new ElementCategoryFilter(BuiltInCategory.OST_PipeAccessory);
- ElementCategoryFilter ductFilter = new ElementCategoryFilter(BuiltInCategory.OST_DuctAccessory);
- ElementFilter filter = new LogicalOrFilter(pipeFilter, ductFilter);
- var specialValves = Document.FilterElements(filter).Where(f => SystemCalcUtil.IsStart(f));
- foreach (var familyInstance in specialValves)
- {
- var connector = familyInstance.GetAllConnectors()
- .FirstOrDefault(c => Regex.IsMatch(c.Description, AppSetting.SourceFlag));
- 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();
- m_RoomStartElements.Add(new StringFlag<Element>(systemTypeName, familyInstance));
- }
- }
- return m_RoomStartElements.Where(f => relationSetting.IsMatchSystem(f.Flag)).Select(f => f.Instance)
- .ToList();
- }
- #endregion
- #region 设备节点获取
- /// <summary>
- /// 模型中包含的设备
- /// </summary>
- public Dictionary<string, List<FamilyInstance>> RevitEquipments { get; private set; }
- /// <summary>
- /// 通过设备类型获取相关设备
- /// </summary>
- /// <returns></returns>
- private List<FamilyInstance> GetEquipments(string category)
- {
- if (RevitEquipments == null)
- {
- var doc = Document;
- var fies = doc.FilterElements<FamilyInstance>();
- List<StringFlag<FamilyInstance>> original = new List<StringFlag<FamilyInstance>>();
- 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<FamilyInstance>(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<FamilyInstance> result);
- return result ?? new List<FamilyInstance>();
- }
- #endregion
- #region 数据解析方法
- /// <summary>
- /// 解析当前楼层系统数据
- /// </summary>
- /// <param name="context"></param>
- public virtual void Parse(SystemComputerContext context)
- {
- if (UseLevel == null)
- return;
- 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<FloorDrawRecord> drawRecords = new List<FloorDrawRecord>();
- List<FloorRelationRecord> relationRecords = new List<FloorRelationRecord>();
- #region 计算拓扑树形结构
- /*
- * 1、遍历开始点的限制:特殊阀门,指定标注的Connector;立管,已连接连接件;空间,相交风管元素;
- * 2、根据拓扑图关联的对象信息,找到系统关联的设备生成节点。如果没有遍历到要独立生成
- * 3、要不要显示端头管所在空间的位置
- */
- var startNodes = GetStartNodes();
- List<int> useIds = new List<int>();
- List<MEPCurve> verticalMepCurves = new List<MEPCurve>();
- for (int i = 0; i < startNodes.Count; i++)
- {
- var startNode = startNodes[i];
- var useRelation = relationSetting.GetFirstMatchSystem(startNode.Flag);
- if (useRelation == null)
- continue;
- 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())));
- 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 roomStartElements = GetRoomStartNodes(relationSetting);
- var useEquipments = ParseMachineRoomData(context, relationSetting, roomStartElements);
- useEquipments = useEquipments.Distinct().ToList();
- #endregion
- //获取没有使用过的对象节点
- List<FamilyInstance> 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<string> useSystems = new List<string>();
- 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<MEPCurve> mepCurves, SystemComputerContext context, RelationTypeShell relationSetting)
- {
- var result = new List<VerticalPipe>();
- var spaces = Document.GetElements<SpatialElement>(BuiltInCategory.OST_MEPSpaces).OfType<Space>();
- 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<BinaryRelationItem>();
- 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<EquipmentNode>() { 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 初始化名称,分类
- /// <summary>
- /// 初始化节点扩展数据
- /// </summary>
- /// <param name="context"></param>
- /// <param name="node"></param>
- private void BuildElementNodeData(SystemComputerContext context, ElementTreeNode node)
- {
- Queue<ElementTreeNode> nodeQueue = new Queue<ElementTreeNode>();
- 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 解析机房数据
- /// <summary>
- /// 解析机房数据
- /// </summary>
- /// <param name="context"></param>
- /// <param name="relationSetting"></param>
- /// <param name="startElements"></param>
- protected List<string> ParseMachineRoomData(SystemComputerContext context, RelationTypeShell relationSetting,
- List<Element> startElements)
- {
- /*
- *1、解析过程中尽量少处理和后续相关的数据
- * 2、设备整理,带缓存的设备信息读取
- */
- List<string> useEquipments = new List<string>();
- var relationType = relationSetting.RelationItem.Type;
- GplotGraphParse parse = new GplotGraphParse(new GplotGraphSetting(relationSetting));
- List<Element> useStartElements = new List<Element>(startElements);
- var graphs = parse.CreateGplotGraphs(useStartElements);
- graphs.RemoveAll(c => c.Vertexes.All(v => !v.IsRealEquipment()));
- #region 加载设备显示信息
- foreach (var elementEdgesArray in graphs)
- {
- var vertexes = elementEdgesArray.Vertexes.Where(v => v.Children.Count == 0);
- foreach (var elementsVertex in vertexes)
- {
- var equipmentItem = elementsVertex.GetEquipment();
- if (equipmentItem == null)
- {
- continue;
- }
- if (string.IsNullOrWhiteSpace(equipmentItem.BimId))
- {
- continue;
- }
- if (equipmentItem.ElementType == ElementType.Space)
- {
- var spaceIem = context.Rooms.GetItem(equipmentItem.BimId);
- if (spaceIem != null)
- {
- equipmentItem.Name = spaceIem.GetDisplay();
- }
- }
- else if (equipmentItem.ElementType == ElementType.Equipment)
- {
- var equipment = context.EquipmentItems.GetItem(equipmentItem.BimId);
- if (equipment != null)
- {
- equipmentItem.Name = equipment.GetDisplay();
- }
- }
- }
- }
- #endregion
- #region 生成图形数据
- var drawData = SystemParseManager.CreateRoomDrawing(graphs);
- MachineRoomDrawRecord record = new MachineRoomDrawRecord();
- //record.Id = Document.GetMd5();
- record.RelationName = relationSetting.RelationItem.Name;
- record.FloorName = MBIInfoUtil.GetFloorNameByLevel(UseLevel.Name);
- record.NodePaths = drawData;
- context[relationType].MachineRoomDrawRecords.Add(record);
- #endregion
- #region 生成关系数据
- var relations = SystemParseManager.CreateRoomRelation(graphs);
- 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<string>() { 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 解析机房数据
- /// <summary>
- /// 根据revitId获取bimId
- /// </summary>
- /// <param name="revitId"></param>
- /// <returns></returns>
- private string CreateBimId(string revitId)
- {
- return string.Format($"{Document.PathName.GetFileName()}:{revitId}");
- }
- }
- }
|