123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- /*-------------------------------------------------------------------------
- * 功能描述:FloorSpaceItems
- * 作者:xulisong
- * 创建时间: 2018/12/21 14:41:27
- * 版本号: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 FWindSoft.Data;
- using SAGA.DotNetUtils.Extend;
- using SAGA.MBI.DataArrange;
- using SAGA.MBI.Model;
- using SAGA.Models;
- using SAGA.RevitUtils;
- using SAGA.RevitUtils.Extends;
- namespace SAGA.GplotRelationComputerManage
- {
- [Flags]
- public enum AdjanceElementType
- {
- None=0,
- Wall=1,
- VirtualWall=1<<1,
- Door=1<<2,
- Window=1<<3,
- /// <summary>
- /// 垂直邻接
- /// </summary>
- Vertical=1<<4,
- /// <summary>
- /// 垂直洞口,交通
- /// </summary>
- VerticalOpening = 1 << 5,
- }
- /// <summary>
- ///模型解析对应的楼层空间数据
- /// </summary>
- public class FloorSpaceItems
- {
- #region 构造函数
- /// <summary>
- /// 初始化解析类
- /// </summary>
- /// <param name="doc"></param>
- public FloorSpaceItems(Document doc)
- {
- Document = doc;
- Doors = new Dictionary<string, List<FamilyInstance>>();
- Windows = new Dictionary<string, List<FamilyInstance>>();
- Spaces = new List<Space>();
- ComputerSpaceItems = new List<ComputerSpaceItem>();
- InitData();
- }
- #endregion
- #region 属性相关
- /// <summary>
- /// 关联模型信息
- /// </summary>
- public Document Document { get; private set; }
- /// <summary>
- /// 关联门信息
- /// </summary>
- public Dictionary<string,List<FamilyInstance>> Doors { get; private set; }
- /// <summary>
- /// 关联窗体信息
- /// </summary>
- public Dictionary<string, List<FamilyInstance>> Windows { get; private set; }
- /// <summary>
- /// 关联空间信息
- /// </summary>
- public List<Space> Spaces { get; private set; }
- /// <summary>
- /// 空间计算数据
- /// </summary>
- public List<ComputerSpaceItem> ComputerSpaceItems { get; private set; }
- #endregion
- private bool m_IsInited;
- public void InitData()
- {
- if (!m_IsInited)
- {
- var doc = Document;
- Doors = doc.GetElements<FamilyInstance>(BuiltInCategory.OST_Doors).GroupBy(e =>
- {
- var host = e.Host;
- if (host == null)
- return "-1";
- return host.Id.IntegerValue.ToString();
- }).ToDictionary(g => g.Key, g => g.ToList());
- Windows = doc.GetElements<FamilyInstance>(BuiltInCategory.OST_Windows).GroupBy(e =>
- {
- var host = e.Host;
- if (host == null)
- return "-1";
- return host.Id.IntegerValue.ToString();
- }).ToDictionary(g => g.Key, g => g.ToList());
- Spaces = doc.GetElements<SpatialElement>(BuiltInCategory.OST_MEPSpaces).OfType<Space>().Where(s=>s.Area>0.001).ToList();
- ComputerSpaceItems = Spaces.Select(s => new ComputerSpaceItem(s)).ToList();
- m_IsInited = true;
- }
- }
- #region 持久缓存数据
- private Dictionary<string, SgSpace> m_SaveSpaces = new Dictionary<string, SgSpace>();
- /// <summary>
- /// 获取空间持久数据【缓存没有的话,创建新对象,并加入缓存】
- /// </summary>
- /// <param name="space"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public SgSpace GetSpace(Space space,SpaceComputerContext context)
- {
- string key = space.GetBimId();
- if (m_SaveSpaces.TryGetValue(key, out SgSpace useSpace))
- {
- return useSpace;
- }
- useSpace = context.NewSpace(space);
- m_SaveSpaces[key] = useSpace;
- return useSpace;
- }
- #endregion
- /// <summary>
- /// 解析空间关系
- /// </summary>
- public void Parse(SpaceComputerContext context)
- {
- //初始化空间信息
- Spaces.ForEach(s => GetSpace(s, context));
- CurrentFloorParse(context);
- UpFloorParse(context);
- #region 保存缓存数据
- var doc = Document;
- var id = Regex.Replace(doc.PathName, @".+\\(\w+)\\(\w+).rvt$", "$1-$2");
- var saveName = DalProjectTree.GetFloorNameByFloorId(id.Split('-')[1]);
- var levels = doc.GetLevels();
- string levelName = saveName;
- var currLevels = levels.FirstOrDefault(t => t.Name.IndexOf("-saga") > -1);
- if (currLevels != null) levelName = currLevels.Name;
- FloorSpaceData floorData = new FloorSpaceData
- {
- Name = saveName,
- Id = id,
- LevelName = levelName.Replace("-saga", "")
- };
- m_SaveSpaces.Values.ToList().ForEach(s => floorData.EndPoints.Add(s));
- //获取标高名称,并按高度排序
- List<string> levelNames = levels.OrderBy(t => t.Elevation).Where(t => Regex.IsMatch(t.Name, "[F|B]")).Select(t => t.Name.Replace("-saga", "")).ToList();
- DrawDataServer.SaveSpaceFloorData(new List<FloorSpaceData>() { floorData }, levelNames);
- #endregion
- }
- /// <summary>
- /// 本层空间关系解析
- /// </summary>
- /// <param name="context"></param>
- private void CurrentFloorParse(SpaceComputerContext context)
- {
- BinaryRelationCollection<Space, AdjanceElementType> spaceRelations =
- new BinaryRelationCollection<Space, AdjanceElementType>(false,space=>space.Id.IntegerValue.ToString());
- spaceRelations.SetSetting(new BinaryCollectionSetting<Space, AdjanceElementType>()
- {UpdateAction = (o, n) => o.Value | n.Value});
- #region 本层关系处理
- //展开空间关系数据
- var flatSpaceItems = FlatSpaceEdges(Spaces);
- var groupSpaces = flatSpaceItems.GroupBy(t => t.EdgeElement.Id.IntegerValue).ToList();
- var relations = CalcCombineRelations(groupSpaces.ToList().Select(g => g.Key).ToList());
- for (int i = 0; i < groupSpaces.Count; i++)
- {
- var baseSpace = groupSpaces[i];
- var rels = relations.Where(c => !c.IsHandled && c.Contains(baseSpace.Key)).ToList();
- List<SpaceEdgeInfo> refEdgeInfos = new List<SpaceEdgeInfo>(baseSpace.ToList());
- foreach (var rel in rels)
- {
- rel.IsHandled = true;
- var anotherId = rel.GetAnother(baseSpace.Key);
- if (anotherId == baseSpace.Key)
- {
- continue;
- }
- var anSpace = groupSpaces.FirstOrDefault(g => g.Key == anotherId);
- if (anSpace != null)
- {
- refEdgeInfos.AddRange(anSpace.ToList());
- }
- }
- for (int j = 0; j < refEdgeInfos.Count; j++)
- {
- var baseEdge = refEdgeInfos[j];
- for (int k =j + 1; k < refEdgeInfos.Count; k++)
- {
- var refEdge = refEdgeInfos[k];
- var type = JudgeAdjancentSpace(baseEdge, refEdge);
- if (type != AdjanceElementType.None)
- {
- BinaryRelationItem<Space, AdjanceElementType> item =
- new BinaryRelationItem<Space, AdjanceElementType>(baseEdge.Space, refEdge.Space)
- { Value = type };
- spaceRelations.Update(item);
- }
- }
- }
- }
- #endregion
- #region 整理关联数据
- foreach (var binaryItem in spaceRelations)
- {
- SpaceRelatedEnum relationType= SpaceComputerManager.GetRelationEnum(binaryItem.Value);
- var space1 = GetSpace(binaryItem.First, context);
- space1.AdjacentSpaces.Add(new AdjacentSpace() {Space = context.NewSpace(binaryItem.Second),RelatedEnum= relationType });
- var space2 = GetSpace(binaryItem.Second, context);
- space2.AdjacentSpaces.Add(new AdjacentSpace() { Space = context.NewSpace(binaryItem.First), RelatedEnum = relationType });
- }
- #endregion
- }
- /// <summary>
- /// 上下层空间关系解析
- /// </summary>
- /// <param name="context"></param>
- private void UpFloorParse(SpaceComputerContext context)
- {
- #region 上下层关系处理
- /*1、从下往上计算,则可以利用现有缓存
- 2、如果上一层是夹层,则继续找夹层的上一层,。处理这层中没有分配上下关系的空间
- */
- var currentDoc = Document;
- var currentSpaces = this.ComputerSpaceItems;
- currentSpaces.ForEach(c => c.IsHandled = false);
- do
- {
- var floorId = currentDoc.PathName.GetFileName();
- var upFloor = DalProjectTree.GetUpperFloor(floorId);
- if (upFloor == null)
- break;
- var upFloorItems = context.GetFloorItems(upFloor.FullPath);
- if (upFloorItems == null)
- return;
-
- var upSpaces = upFloorItems.ComputerSpaceItems;
- foreach (var currentSpace in currentSpaces)
- {
- if (currentSpace.IsHandled)
- continue;
- var space1 = GetSpace(currentSpace.Space, context);
- foreach (var upSpace in upSpaces)
- {
- var type= JudgeUpAdjancentSpace(currentSpace, upSpace);
- if (type != AdjanceElementType.None)
- {
- currentSpace.IsHandled = true;
- SpaceRelatedEnum relationType = SpaceComputerManager.GetRelationEnum(type);
- var refSpace = context.NewSpace(upSpace.Space);
- space1.UpElements.Add(new AdjacentSpace() { Space = refSpace, RelatedEnum = relationType });
- }
- }
-
- }
- if (upFloor.FloorType == "4") //夹层为4
- {
- currentDoc = upFloorItems.Document;
- }
- else
- {
- break;
- }
- } while (true);
- #endregion
- }
- #region 展开空间与边界的关联关系
- /// <summary>
- /// 展开空间与边的关系
- /// </summary>
- /// <param name="spaces"></param>
- /// <returns></returns>
- private List<SpaceEdgeInfo> FlatSpaceEdges(List<Space> spaces)
- {
- var lSpaces = new List<SpaceEdgeInfo>();
- Document doc = Document;
- foreach (var space in spaces)
- {
- IList<IList<BoundarySegment>> segments = space.GetBoundarySegments(new SpatialElementBoundaryOptions());
- foreach (IList<BoundarySegment> boundarySegments in segments)
- {
- foreach (var segment in boundarySegments)
- {
- //去除不能构成边的元素
- if (segment.ElementId.IntegerValue != -1)
- {
- Curve wallLine = null;
- var elem = doc.GetElement(segment.ElementId);
- var type = typeof(object);
- //这里只处理墙和分隔符,跨长度处理
- #region 增加关系对象
- if (elem is Wall wall)
- {
- wallLine = wall.Location.GetCurve();
- type = typeof(Wall);
- }
- else if (elem is ModelCurve modelCurve)
- {
- wallLine = modelCurve.GetCurve();
- type = typeof(ModelCurve);
- }
- else
- {
- continue;
- }
- Curve segCurve1 = segment.GetCurve();
- lSpaces.Add(new SpaceEdgeInfo()
- {
- Space = space,
- Edge = wallLine,
- SegEdge = segCurve1,
- EdgeElement = elem,
- EType = type
- });
- #endregion
- }
- }
- }
- }
- return lSpaces;
- }
- #endregion
- #region 构件合并整合
- /*
- * 1、合并间距较小的构件看成一个构件关系
- * 2、可合并构件关系为两两关系,且关系不支持传递。如a->b,b->c 不能推导出 a->c
- * 3、在计算空间关系时,动态关联上相关id去计算空间关系
- */
- /// <summary>
- /// 计算可合并关联
- /// </summary>
- /// <param name="ids"></param>
- private BinaryRelationCollection<int> CalcCombineRelations(List<int> ids)
- {
- BinaryRelationCollection<int> relations = new BinaryRelationCollection<int>(false);
- if (!ids.Any() || ids.Count < 2)
- return relations;
- var doc = Document;
- FilteredElementCollector collectors =
- new FilteredElementCollector(doc, ids.Select(id => new ElementId(id)).ToList());
- collectors.WhereElementIsNotElementType();
- var calcElements = collectors.ToElements();
- Dictionary<int, ElementGraphicItem> tempItems = new Dictionary<int, ElementGraphicItem>();
- for (int i = 0; i < calcElements.Count; i++)
- {
- var outElement = calcElements[i];
- var outItem = GetGraphicItem(tempItems, outElement);
- if (outItem == null)
- {
- continue;
- }
- #region 内部循环
- for (int j = i + 1; j < calcElements.Count; j++)
- {
- var inElement = calcElements[j];
- var inItem = GetGraphicItem(tempItems, inElement);
- if (inItem == null)
- {
- continue;
- }
- if (outItem.Location.IsParallel(inItem.Location)) //平行
- {
- //间距小于两个厚度之和的一半
- var basePoint = outItem.Location.StartPoint();
- var project = inItem.Location.GetProjectPt(basePoint);
- var length = (basePoint - project).GetLength();
- if (((outItem.Width + inItem.Width) / 2.0d).IsThanEq(length))
- {
- relations.Add(new BinaryRelationItem<int>(outElement.Id.IntegerValue,
- inElement.Id.IntegerValue));
- }
- }
- #endregion
- }
- }
- return relations;
- }
- private ElementGraphicItem GetGraphicItem(Dictionary<int, ElementGraphicItem> dic, Element ele)
- {
- if (dic.TryGetValue(ele.Id.IntegerValue, out ElementGraphicItem item))
- {
- return item;
- }
- item = ElementGraphicItem.CreateItem(ele);
- if (item != null)
- {
- dic[ele.Id.IntegerValue] = item;
- }
- return item;
- }
- /// <summary>
- /// 元素集合条目【内部算法使用】
- /// </summary>
- private class ElementGraphicItem
- {
- /// <summary>
- /// 位置
- /// </summary>
- public Line Location { get; set; }
- /// <summary>
- /// 宽度
- /// </summary>
- public double Width { get; set; }
- /// <summary>
- /// 创建几何使用Item.
- /// </summary>
- /// <param name="element"></param>
- /// <returns></returns>
- public static ElementGraphicItem CreateItem(Element element)
- {
- double width = 0;
- if (element is Wall wall)
- {
- width = wall.WallType.GetParameterDouble(BuiltInParameter.WALL_ATTR_WIDTH_PARAM);
- }
- Line line= element.GetLocationCurve().GetLine();
- if (line != null)
- {
- return new ElementGraphicItem() {Width = width, Location = line};
- }
- return null;
- }
- }
- #endregion
- #region 邻接关系判断
- /// <summary>
- /// 判断两个空间,在指定边上的相交关系
- /// </summary>
- /// <param name="space1"></param>
- /// <param name="space2"></param>
- /// <returns></returns>
- public AdjanceElementType JudgeAdjancentSpace(SpaceEdgeInfo space1, SpaceEdgeInfo space2)
- {
- var result=AdjanceElementType.None;
- if(space1.Space.Id.IntegerValue==space2.Space.Id.IntegerValue)
- return result;
- /*先判断是否是虚拟墙。如果是实体墙,则进一步判断是否所有门窗之间的关系;
- 两个space,可能不是公用一个Eelment,而是通过关联产生的
- */
- //平行直线和弧线的投影
- var baseCurve = space1.Edge;//spac1的edge和space2的edge平行
- Curve curve1 = GetProjectCurve(baseCurve, space1.SegEdge);
- Curve curve2 = GetProjectCurve(baseCurve, space2.SegEdge);
- IntersectionResultArray ira;
- var isConn = curve2.Intersect(curve1, out ira) != SetComparisonResult.Disjoint;
- if (!isConn||(ira != null && ira.Size == 1))
- {
- return result;
- }
- #region 虚拟墙判断
- var virType = typeof(ModelCurve);
- if (space1.EType == virType && space2.EType == virType)
- {
- return AdjanceElementType.VirtualWall;
- }
- #endregion
- result = AdjanceElementType.Wall;//必然墙相连
- #region 门窗判断
- List<Wall> walls = new List<Wall>();
- foreach (var spaceEdgeInfo in new []{space1,space2})
- {
- if (spaceEdgeInfo.EType == typeof(Wall))
- {
- if (walls.Any(w => w.Id == spaceEdgeInfo.EdgeElement.Id))
- {
- continue;
- }
- walls.Add(spaceEdgeInfo.EdgeElement as Wall);
- }
- }
- if (walls.Any())
- {
- result = result | AdjanceElementType.Wall;
- var doors = new List<FamilyInstance>();
- var windows = new List<FamilyInstance>();
- foreach (var wall in walls)
- {
- List<FamilyInstance> tempDoors = new List<FamilyInstance>();
- if (Doors.TryGetValue(wall.Id.IntegerValue.ToString(), out tempDoors))
- {
- doors.AddRange(tempDoors);
- }
- List<FamilyInstance> tempWindows = new List<FamilyInstance>();
- if (Windows.TryGetValue(wall.Id.IntegerValue.ToString(), out tempWindows))
- {
- windows.AddRange(tempWindows);
- }
- }
- List<Curve> edgeCurves = new List<Curve>() {space1.SegEdge, space2.SegEdge};
- if (doors.Any(d => edgeCurves.All(c => c.IsContain(c.GetProjectPt(d.GetLocationPoint())))))
- {
- result = result | AdjanceElementType.Door;
- }
- if (windows.Any(w => edgeCurves.All(c => c.IsContain(c.GetProjectPt(w.GetLocationPoint())))))
- {
- result = result | AdjanceElementType.Window;
- }
- }
-
- #endregion
-
- return result;
- }
- /// <summary>
- /// 获取Curve1在Curve2上的投影【两线为平行关系的直线和弧线】【可简化】
- /// </summary>
- /// <param name="projectCurve"></param>
- /// <param name="curve"></param>
- /// <returns></returns>
- private Curve GetProjectCurve(Curve projectCurve, Curve curve)
- {
- var startPoint = projectCurve.GetProjectPt(curve.StartPoint());
- var endPoint = projectCurve.GetProjectPt(curve.EndPoint());
- if (projectCurve is Arc)
- {
- //弧形应该是法向投影
- var middle = projectCurve.GetProjectPt((startPoint + endPoint) / 2);
- return Arc.Create(startPoint, endPoint, middle);
- }
- return Line.CreateBound(startPoint, endPoint);
- }
- #endregion
- #region 上下层关系判断
- /// <summary>
- /// 判断两个空间是否是上下相交关系
- /// </summary>
- /// <param name="aFSpace"></param>
- /// <param name="bSpace"></param>
- /// <returns></returns>
- public AdjanceElementType JudgeUpAdjancentSpace(ComputerSpaceItem aFSpace, ComputerSpaceItem bSpace)
- {
- AdjanceElementType result = AdjanceElementType.None;
- if (!aFSpace.Box.Intersects(bSpace.Box, 0))
- {
- return result;
- }
- if (ClosedIntersect(aFSpace.ZeroCurves, bSpace.ZeroCurves))
- {
- result = AdjanceElementType.Vertical;
- if (SpaceComputerManager.IsCrossFunType(aFSpace.FuncType) && SpaceComputerManager.IsCrossFunType(bSpace.FuncType))
- {
- result = result | AdjanceElementType.VerticalOpening;
- }
- }
- return result;
- }
- public bool ClosedIntersect(List<Curve> closed1, List<Curve> closed2)
- {
- //判断所有的线是否有相交
- foreach (var curve1 in closed1)
- {
- if (curve1.IsIntersectPoly(closed2)) return true;
- }
- //判断是否包含
- foreach (var curve in closed1)
- {
- if (curve.StartPoint().PointInPolygon(closed2)) return true;
- }
- return closed2.Any(curve => curve.StartPoint().PointInPolygon(closed1));
- }
- #endregion
- }
- }
|