using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Newtonsoft.Json.Linq;
using SAGA.DotNetUtils.Extend;
using SAGA.MBI.DataArrange;
using SAGA.MBI.Model;
using SAGA.MBI.RequestData;
using SAGA.Models;
using SAGA.RevitUtils;
using SAGA.RevitUtils.Extends;
using Point = System.Windows.Point;
namespace SAGA.GplotRelationComputerManage
{
///
/// 空间关系
///
public class ReadSpaceCommand
{
List m_doors;
List m_windows;
private Dictionary> m_levelSpaceData;
//存放所有层的楼层名称与所有空间边线
Dictionary /*边线*/>> allSpace =
new Dictionary>>();
///
/// 缓存所有楼层的空间,避免重复加载数据
///
Dictionary /*空间*/> allSpaces =
new Dictionary>();
///
/// 缓存所有转换后的空间对象
///
List allSgSpaces = new List();
private bool m_isDraw = false;
List m_sgSpaces;
private Dictionary m_dicServerSpace;
List> m_connectionLine = new List>();
private Document m_doc;
//需要进行上下比较房间类型
private List roomFunCtype = new List() { "140","150","1A0","1B0" };
///
/// 初始化数据集合
///
void Init()
{
m_doors = new List();
m_windows = new List();
m_levelSpaceData = new Dictionary>();
m_sgSpaces = new List();
}
///
/// 向集合内添加空间,防止空间重复
///
///
public void AddSpaces(SgSpace sgSpace)
{
var space = m_sgSpaces.FirstOrDefault(t => t.Id == sgSpace.Id);
if (sgSpace != null)
{
m_sgSpaces.Remove(space);
}
m_sgSpaces.Add(sgSpace);
}
///
/// 对所有模型进行空间计算
///
public void Computer()
{
//缓存所有空间数据
//查询所有设备
// var str = new string[] { "Si" };//元空间为Si
//List datas = CommonConvert.QueryObjectInfoByTypes(str);
//m_dicServerSpace = new Dictionary();
//datas.ForEach(t =>
//{
// var bimId = GetValue(t, "BIMID");
// if (!string.IsNullOrEmpty(bimId))
// {
// m_dicServerSpace[bimId] = t;
// }
//});
//打开所有楼层数据
//Stopwatch watch = new Stopwatch();
//watch.Start();
var fileInfos = RevitModelPath.GetAllRevitFiles();//.Where(t => t.IndexOf("71062c") > -1);
SpaceComputerContext context = new SpaceComputerContext();
foreach (var fileInfo in fileInfos)
{
if (File.Exists(fileInfo))
{
//var uiApp = ExternalDataWrapper.Current.UiApp.Application;
// var doc = uiApp.OpenDocumentFile(fileInfo);
FloorSpaceItems floorItems = context.GetFloorItems(fileInfo);
floorItems.Parse(context);
floorItems.Document.Close();
//ComputerSpace(doc);
}
}
//MessageShow.Infomation((watch.ElapsedMilliseconds / 1000).ToString());
//watch.Stop();
//MessageShow.Infomation((watch.ElapsedMilliseconds / 1000).ToString());
}
///
/// 获取指定属性的值
///
///
///
///
public string GetValue(JObject equip, string propertyName)
{
// equip.GetValue("infos")
string result = "";
if (equip != null)
{
result = equip["infos"][propertyName] + "";
}
return result;
}
///
/// 读取Document里面的所有空间
///
///
///
///
List GetSpaces(Document doc, string filePath = "")
{
if (string.IsNullOrEmpty(filePath))
filePath = doc.PathName;
var modelId = Path.GetFileNameWithoutExtension(filePath);
Debug.Assert(modelId != null, nameof(modelId) + " != null");
if (allSpaces.ContainsKey(modelId))
{
return allSpaces[modelId];
}
if (doc == null)
{
if (File.Exists(filePath))
{
var uiApp = ExternalDataWrapper.Current.UiApp.Application;
doc = uiApp.OpenDocumentFile(filePath);
}
else
return new List();
}
List spaces = doc.GetAllElements().Where(e => e is Space space && !space.Area.IsZero()).Cast().ToList();
allSpaces.Add(modelId, spaces);
return spaces;
}
///
/// 将Revit空间数据转换成可序列化的数据
///
///
///
///
SgSpace GetSgSpace(Space space, bool isCreate = true)
{
var sgSpace = allSgSpaces.FirstOrDefault(t => t.Id == space.Id.ToString());
if (sgSpace == null || !isCreate)
{
var floorId = space.Document.PathName.GetFileName();
var bimID = string.Format($"{floorId}:{space.Id.ToString()}");
var localName = space.Name;
var spaceType = string.Empty;
m_dicServerSpace.TryGetValue(bimID, out JObject jo);
if (jo != null)
{
localName = GetValue(jo, "RoomLocalName");
spaceType=GetValue(jo, "RoomFuncType");
}
sgSpace = new SgSpace()
{
Id = space.Id.ToString(),
Name =string.IsNullOrEmpty(localName)? space.Name: localName,
Point = space.Location.GetPoint().ToW2DPoint(),
// Point = GetCenter(space).ToW2DPoint(),
RoomFuncType = spaceType,
BoundarySegment = ConvertBoundarySegmentTo2D(new LvSpace(space))
};
if (isCreate)
allSgSpaces.Add(sgSpace);
return sgSpace;
}
return sgSpace;
}
///
/// 计算空间关系
///
///
public void ComputerSpace(Document doc)
{
m_doc = doc;
Init();
m_doors = doc.GetElements(BuiltInCategory.OST_Doors);
m_windows = doc.GetElements(BuiltInCategory.OST_Windows);
List spaces = GetSpaces(doc);
#region 计算平面拓扑
System.Diagnostics.Debug.WriteLine(DateTime.Now + "平面计算开始");
//转换所有空间
var dataSpaces = ConvertSpace(spaces);
//根据边上的Element分组
var groupSpaces = dataSpaces.GroupBy(t => t.EdgeElement.Id.IntegerValue).ToList();
//合并公共构建,如果是面层墙则进行合并
var datas = CombinElement(groupSpaces);
foreach (var groupSpace in datas)
{
var lSpaces = groupSpace.Value;
var count = lSpaces.Count;
if (count > 1)
{
for (int i = 0; i < count; i++)
{
var ls1 = lSpaces[i];
var mySpace = ls1.Space;
SgSpace currSgSpace = GetSgSpace(mySpace);
AddSpaces(currSgSpace);
for (int j = i + 1; j < count; j++)
{
var ls2 = lSpaces[j];
var space = ls2.Space;
if (mySpace.Id.IsEqual(space.Id)) continue;
var sgSpace = GetSgSpace(space, false);
//如果关系已经存在
if ((sgSpace.AdjacentSpaces.Any(t => t.Space.Id == currSgSpace.Id) || currSgSpace.AdjacentSpaces.Any(t => t.Space.Id == sgSpace.Id))) continue;
//分别做投影
Curve curve1 = GetProjectLine(ls1.Edge, ls1.SegEdge);
Curve curve2 = GetProjectLine(ls1.Edge, ls2.SegEdge);
//判断投影是否相交或者包含
//var isConn = curve2.Intersect(curve1) != SetComparisonResult.Disjoint;
IntersectionResultArray ira;
var isConn = curve2.Intersect(curve1, out ira) != SetComparisonResult.Disjoint;
if (ira != null && ira.Size == 1) continue;
var isVirtual = ls1.EType == typeof(ModelCurve);
if (isConn)
{
//判断关系
var spaceRelated = isVirtual
? SpaceRelatedEnum.All
: JudgeDoorAndWindow(ls1.EdgeElement, curve1,
curve2);
var adjacentSpace = new AdjacentSpace()
{
Space = sgSpace,
RelatedEnum = spaceRelated
};
currSgSpace.AdjacentSpaces.Add(adjacentSpace);
m_connectionLine.Add(new List()
{
currSgSpace.Point,
sgSpace.Point
});
}
}
}
}
}
#endregion
System.Diagnostics.Debug.WriteLine(DateTime.Now + "平面计算结束");
var name = doc.Title;
//上层模型名字
var upFloor = GetUpFloorKey(name);
if (upFloor != null)
{
var upSpaces = GetSpaces(null, upFloor.FullPath);
var upLvSpaces = upSpaces.Select(t => new LvSpace(t)).ToList();
var currLvSpaces = spaces.Select(t => new LvSpace(t));
foreach (var lvSpace in currLvSpaces)
{
ComputerUpDownRelationship(lvSpace, upLvSpaces);
}
//判断上一层是否为夹层
if (upFloor.FloorType == "4") //夹层为4
{
//取出夹层的上一层
var upUpFloor = GetUpFloorKey(upFloor.FullPath);
if (upUpFloor != null)
{
var upUpSpaces = GetSpaces(null, upUpFloor.FullPath);
var upUpLvSpaces = upUpSpaces.Select(t => new LvSpace(t)).ToList();
foreach (var lvSpace in currLvSpaces.Where(t => t.IsPaired == false))
{
ComputerUpDownRelationship(lvSpace, upUpLvSpaces);
}
}
}
}
//保存数据到数据库
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_sgSpaces.ForEach(s => floorData.EndPoints.Add(s));
//获取标高名称,并按高度排序
List 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() { floorData }, levelNames);
//换成楼层空间数据
if (m_levelSpaceData.Count > 0 && !allSpace.ContainsKey(name))
allSpace.Add(name, m_levelSpaceData);
}
///
/// 合并公共构件
///
///
///
private List>> CombinElement(List> eleDatas)
{
var datas = eleDatas.ToDictionary(t => t.Key, t => t.ToList()).ToList();
for (int i = datas.Count - 1; i >= 0; i--)
{
var d1 = datas[i];
var e1 = d1.Value.FirstOrDefault().EdgeElement;
var thickness1 = 0d;
var line1 = GetElementLine(e1, out thickness1);
if(line1==null)continue;
var middle = line1.MiddlePoint();
for (int j = i - 1; j >= 0; j--)
{
j = Math.Min(datas.Count-1, j);
var d2 = datas[j];
if (d2.Key == d1.Key) continue;
var e2 = d2.Value.FirstOrDefault().EdgeElement;
var thickness2 = 0d;
var line2 = GetElementLine(e2, out thickness2);
if(line2==null||line1==null)continue;
if (line1.IsParallel(line2))//平行
{
//间距小于两个厚度之和的一半
var project = line2.GetProjectPt(middle);
var length = (middle - project).GetLength();
if (((thickness1 + thickness2) / 2.0d).IsThanEq(length))
{
//将线投影到另外一条线上,两条线必须共线
var projectLine = GetProjectLine(line1, line2);
if (projectLine.Intersect(line1) != SetComparisonResult.Disjoint)
{
//合并两个Element,取长的保留
if (line1.Length < line2.Length)
{
d2.Value.AddRange(d1.Value);
datas.RemoveAll(t => t.Key == (d1.Key));
}
else
{
d1.Value.AddRange(d2.Value);
datas.RemoveAll(t => t.Key == (d2.Key));
}
}
}
}
}
}
return datas;
}
///
/// 获取Element的厚度以及中轴线
///
///
///
///
Line GetElementLine(Element ele, out double width)
{
width = 0;
if (ele is Wall wall)
{
width = wall.WallType.GetParameterDouble(BuiltInParameter.WALL_ATTR_WIDTH_PARAM);
}
return ele.GetLocationCurve().GetLine();
}
///
/// 获取Curve1在Curve2上的投影
///
///
///
///
private Curve GetProjectLine(Curve projectLine, Curve line)
{
var startPoint = projectLine.GetProjectPt(line.StartPoint());
var endPoint = projectLine.GetProjectPt(line.EndPoint());
if (projectLine is Arc)
{
var middle = projectLine.GetProjectPt((startPoint + endPoint) / 2);
return Arc.Create(startPoint, endPoint, middle);
}
return Line.CreateBound(startPoint, endPoint);
}
///
/// 判断当前两个空间是否有门窗
///
///
///
///
///
private SpaceRelatedEnum JudgeDoorAndWindow(Element wall, Curve curve1, Curve curve2)
{
var wallId = wall.Id;
var wallWidth = (wall as Wall)?.WallType.Width;
var z = curve1.StartPoint().Z;
SpaceRelatedEnum spaceRelated = SpaceRelatedEnum.Adjacent;
var doors = m_doors.Where(t => t.Host.Id.IsEqual(wallId));
var windows = m_windows.Where(t => t.Host.Id.IsEqual(wallId));
Predicate isHost = (point) =>
{
point = point.NewZ(z);
//向两个线上做投影
var point1 = curve1.GetProjectPt(point, false);
var point2 = curve2.GetProjectPt(point, false);
//定位点到两个投影的必须小于墙厚
return (point - point1).GetLength() < wallWidth && (point - point2).GetLength() < wallWidth;
};
if (doors.Any(t => isHost(t.GetLocationPoint())))
spaceRelated = spaceRelated | SpaceRelatedEnum.Crossing | SpaceRelatedEnum.Ventilation;
if (windows.Any(t =>
isHost(t.GetLocationPoint())))
spaceRelated = spaceRelated | SpaceRelatedEnum.Radiation | SpaceRelatedEnum.Ventilation;
return spaceRelated;
}
///
/// 计算上层相关联的空间
///
///
///
void ComputerUpDownRelationship(LvSpace space, List upSpaces)
{
var curves = space.ZeroCurves;
var sgSpace = m_sgSpaces.FirstOrDefault(t => t.Id == space.Space.Id.ToString()) ?? GetSgSpace(space.Space, false);
foreach (var upSpace in upSpaces)
{
if (ClosedIntersect(upSpace.ZeroCurves, curves))
{
space.IsPaired = true;
var s = GetSgSpace(upSpace.Space, false);
var related = SpaceRelatedEnum.Adjacent;
//判断上下关系
//TODO:此处取出空间类型属性,如果一致则建立关系,此处交通必须是一对一,如果不是,则不建立关系(1对多不建立关系)
if (s.RoomFuncType == sgSpace.RoomFuncType && roomFunCtype.Contains(s.RoomFuncType))
{
related = related | SpaceRelatedEnum.Crossing;
space.UpLvSpaces.Add(upSpace);
}
sgSpace.UpElements.Add(new AdjacentSpace()
{
Space = s,
RelatedEnum = related
});
}
}
}
///
/// 将空间轮廓转换成Win2d
///
///
///
private List> ConvertBoundarySegmentTo2D(LvSpace upSpace)
{
//取出边缘
var datas = new List>();
foreach (var curve in upSpace.ZeroCurves)
{
if (curve is Autodesk.Revit.DB.Line line)
{
// var line = segment.GetCurve().GetLine();
datas.Add(new List(){
line.GetEndPoint(0).ToW2DPoint()
,line.GetEndPoint(1).ToW2DPoint() });
}
else if (curve is Autodesk.Revit.DB.Arc arc)
{
datas.Add(arc.Tessellate().Select(xyz => xyz.ToW2DPoint()).ToList());
}
}
return datas;
}
///
/// 判断两个区域是否相交或者相互包含
///
///
///
///
public bool ClosedIntersect(List closed1, List 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));
}
///
/// 获取上层空间信息
///
/// 楼层名称
/// 上层楼层名称
MFloor GetUpFloorKey(string key)
{
var modelName = System.IO.Path.GetFileNameWithoutExtension(key);
MFloor floor = DalProjectTree.GetUpperFloor(modelName);
return floor;
}
///
/// 将所有空间转换成边集合对象
///
///
///
private List ConvertSpace(List spaces)
{
var lSpaces = new List();
foreach (var space in spaces)
{
//如果空间内有多个柱子,每个柱子相当于一个封闭区域,也是一个List,如果一个空间分隔符或者墙上有一个柱子,所在的空间轮廓就会多出两个边分别是柱子左边,柱子,柱子右边,他们三个的ElementId相同,getCurve不同
IList> segments = space.GetBoundarySegments(new SpatialElementBoundaryOptions());
foreach (IList boundarySegments in segments)
{
foreach (var segment in boundarySegments)
{
//去除不能构成边的元素
if (segment.ElementId.IntegerValue != -1)
{
Curve wallLine = null;
var elem = m_doc.GetElement(segment.ElementId);
var type = typeof(object);
//这里只处理墙和分隔符
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
});
}
}
}
// var edgeCopy=Array.Copy()
}
return lSpaces;
}
}
///
/// 比较轮廓边是否相等
///
public class Comparea : IEqualityComparer
{
public bool Equals(SpaceEdgeInfo x, SpaceEdgeInfo y)
{
return x.Space.Id.IsEqual(y.Space.Id);
}
public int GetHashCode(SpaceEdgeInfo obj)
{
return 0;
}
}
}