/* ==============================================================================
* 功能描述:SpaceExtension
* 创 建 者:Garrett
* 创建日期:2019/6/26 17:40:25
* ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using JBIM.Definition;
using RevitToJBim.Common;
using SAGA.RevitUtils;
using SAGA.RevitUtils.Extends;
using XYZ = Autodesk.Revit.DB.XYZ;
namespace RevitToJBim.Extension
{
///
/// SpaceExtension
///
public static class SpaceExtension
{
static SpaceExtension()
{
UseablePhaseName = ConfigurationManager.AppSettings["UseablePhaseName"];
}
public readonly static string UseablePhaseName;
///
/// 获取系统使用的阶段Id
///
///
///
public static ElementId GetUsePhaseId(this Document doc)
{
var phase = GetUsePhase(doc);
if (phase == null)
{
return ElementId.InvalidElementId;
}
return phase.Id;
}
///
/// 获取系统使用的阶段
///
///
///
public static Phase GetUsePhase(this Document doc)
{
var elements = doc.GetElements(BuiltInCategory.OST_Phases);
foreach (var element in elements)
{
var tempName = element.Name.Replace(" ", "").Trim();
if (UseablePhaseName == tempName)
{
return element;
}
}
return null;
}
public static ElementId GetCurrentPhaseId(this Space space)
{
return space.GetParameterElementId(BuiltInParameter.ROOM_PHASE_ID) ?? ElementId.InvalidElementId;
}
///
/// 判断是否是阶段1的空间
///
///
///
public static bool IsPhase1Space(this Space space)
{
var doc = space.Document;
var useId = GetUsePhaseId(doc);
return space.GetCurrentPhaseId() == useId;
}
///
/// 空间标高是否是当前使用视图标高
///
///
///
public static bool IsViewLevel(this Space space)
{
var doc = space.Document;
var useViewId = doc.GetUseView();
if (useViewId == null)
{
return false;
}
return space.Level?.Id == useViewId.GenLevel?.Id;
}
private static string m_DocTitle;
private static List> m_wallTuples = new List>();
///
/// 缓存墙线数组
///
///
///
private static List> GetWallTuples(Document doc)
{
var title = doc.GetPathNameOrTitle();
if (m_DocTitle != title)
{
m_DocTitle = title;
var allWalls = doc.GetElements();
var tupleWalls = allWalls
.Select(t => new Tuple(t.GetLocationCurve(), t)).ToList();
m_wallTuples = tupleWalls;
}
return m_wallTuples;
}
///
/// 获取空间的外轮廓
///
///
///
public static List GetSpaceOutline(this Space space)
{
List outlines = new List();
try
{
SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
//options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;
var segments = space.GetBoundarySegments(options);
Document doc = space.Document;
double tolerance = doc.Application.ShortCurveTolerance;
//var allWalls = doc.GetElements();
//var tupleWalls = allWalls
// .Select(t => new Tuple(t.GetLocationCurve(), t)).ToList();
var tupleWalls = GetWallTuples(doc);
foreach (var segment in segments)
{
#region 取外轮廓的点
List xyzs = new List();
foreach (BoundarySegment boundarySegment in segment)
{
var segmentElement = space.Document.GetElement(boundarySegment.ElementId);
if (segmentElement is Wall wall)
{
var parallelWalls = GetParallelWalls(wall, tupleWalls);
var segmentCurve = boundarySegment.GetCurve();
var tessellates = segmentCurve.Tessellate();
foreach (XYZ tessellate in tessellates)
{
var wallCurve = wall.GetLocationCurve();
var project = wallCurve.GetProjectPt(tessellate);
var verticalVector = (project - tessellate).Normalize();
var tempXyz = GetOuterXYZ(tessellate, verticalVector, segmentCurve, parallelWalls);
if (tempXyz != null)
xyzs.Add(tempXyz);
}
}
else
{
foreach (XYZ tessellate in boundarySegment.GetCurve().Tessellate())
{
xyzs.Add(tessellate);
}
}
}
#endregion
#region 处理内拐角
int count = xyzs.Count;
/*
* 相邻两条线求交点
* 处理内拐角
*/
for (int i = 0; i < count; i++)
{
if (count < 4) continue;
var p1 = xyzs[i];
int j2 = i + 1 >= xyzs.Count ? i + 1 - count : i + 1;
var p2 = xyzs[j2];
int j3 = i + 2 >= xyzs.Count ? i + 2 - count : i + 2;
var p3 = xyzs[j3];
int j4 = i + 3 >= xyzs.Count ? i + 3 - count : i + 3;
var p4 = xyzs[j4];
if (p2.IsEqual(p3) || p1.DistanceTo(p2) < tolerance || p3.DistanceTo(p4) < tolerance)
continue;
Curve curve1 = Line.CreateBound(p1, p2);
Curve curve2 = Line.CreateBound(p3, p4);
XYZ intersection = curve1.GetIntersection(curve2);
if (intersection == null) continue;
xyzs[j2] = intersection;
xyzs[j3] = intersection;
}
#endregion
//添加起始点,形成闭合区域
if (xyzs.Any())
xyzs.Add(xyzs[0]);
//整理数据
Polygon outLine = new Polygon();
var usePoints = xyzs.Select(xyz => BimConvert.ConvertToXYZ(xyz)).ToList();
outLine.AddRange(usePoints.GetRange(0, usePoints.Count - 1));
StandardUtil.ArrangeLoop(outLine);
outlines.Add(outLine);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
return outlines;
}
private static double m_RedundancySpace = 10d.ToApi();
///
/// 获取平行墙,平行且投影有重叠部分
///
///
///
public static List GetParallelWalls(Wall wall, List> tupleWalls)
{
List walls = new List();
walls.Add(wall);
var curve = wall.GetLocationCurve();
var parallelWallTuples = tupleWalls.Where(t => t.Item1.IsParallel(curve));
int len = walls.Count;
do
{
len = walls.Count;
foreach (Tuple parallelWallTuple in parallelWallTuples)
{
var curve1 = parallelWallTuple.Item1;
var parallelWall = parallelWallTuple.Item2;
var startP11 = CurveExtend.StartPoint(curve1);
var endP11 = CurveExtend.EndPoint(curve1);
double width1 = parallelWall.Width;
for (int i = 0; i < walls.Count; i++)
{
Wall referenceWall = walls[i];
if (walls.Contains(parallelWall)) continue;
var curve2 = referenceWall.GetLocationCurve();
var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
//速度优化
if (startP12.IsOnCurve(curve2))
{
double width2 = referenceWall.Width;
double distacne = startP11.DistanceTo(endP11);
if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
walls.Add(parallelWall);
}
else
{
var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
if (endP12.IsOnCurve(curve2))
{
double width2 = referenceWall.Width;
double distacne = startP11.DistanceTo(endP11);
if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
walls.Add(parallelWall);
}
}
//var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
//var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
////判断是否有重叠部分
//if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2))
//{
// double width2 = referenceWall.Width;
// double distacne = curve1.Distance(curve2);
// if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
// walls.Add(parallelWall);
//}
}
}
} while (len != walls.Count);
return walls;
}
///
/// 获取外廓后的点
///
/// 外廓点
/// 外廓向量
/// 参考Curve
/// 平行墙集合
///
public static XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List walls)
{
XYZ outerXyz = xyz;
double distance = 0;
foreach (Wall wall in walls)
{
/*
* 注意幕墙,没有底面,直接取原始点xyz
*/
List faces = wall.GetBottomFaces();
foreach (PlanarFace face in faces)
{
foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops())
{
foreach (Curve curve in curveLoop)
{
/*
* 1. 获取平行边
* 2. 平行边求投影,投影点形成向量为向外
* 3. 投影点在线上
*/
if (!segmentCurve.IsParallel(curve))
continue;
var projectPt = curve.GetProjectPt(xyz);
var tempVector = (projectPt - xyz).Normalize();
if (projectPt.IsOnCurve(curve) && !projectPt.IsEqual(xyz) && tempVector.IsEqual(verticalVector))
{
var tempDistance = xyz.DistanceTo(projectPt);
if (tempDistance >= distance)
{
distance = tempDistance;
outerXyz = projectPt;
}
}
else
{
/*
* 无投影点,给个默认投影点的情况
* 处理斜边投影不到的情况边上的情况,
* 目前任意取了一个,多个取最近的??
*/
if (outerXyz == null || outerXyz.IsEqual(xyz))
outerXyz = projectPt;
}
}
}
}
}
return outerXyz.NewZ(xyz.Z);
}
}
}