123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- /*-------------------------------------------------------------------------
- * 功能描述:创建空间外轮廓
- * 作者:xulisong
- * 创建时间: 2019/3/21 8:59:02
- * 版本号:v1.0
- * -------------------------------------------------------------------------*/
- using Autodesk.Revit.Attributes;
- using Autodesk.Revit.DB;
- using Autodesk.Revit.DB.Mechanical;
- using Autodesk.Revit.UI;
- using FWindSoft.Revit;
- using FWindSoft.Revit.Menu;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Windows.Shapes;
- using FWindSoft.SystemExtensions;
- using SAGA.DotNetUtils.Extend;
- using SAGA.RevitUtils.Extends;
- using SAGA.RevitUtils.MEP;
- using ExternalCommand = FWindSoft.Revit.ExternalCommand;
- using Line = Autodesk.Revit.DB.Line;
- using DocumentExtension = FWindSoft.Revit.DocumentExtension;
- namespace LRH.Tool
- {
- [Transaction(TransactionMode.Manual)]
- [Regeneration(RegenerationOption.Manual)]
- [Button(ButtonName = "创建空间轮廓线")]
- public class CreateSpaceOutLineCommand : ExternalCommand
- {
- public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
- {
- using (Transaction tran = new Transaction(RevitCore.Doc, "创建空间"))
- {
- try
- {
- tran.Start();
- //var space = RevitCore.UIApp.PickElement("请选择空间", new CommonFilter(t => { return t is Space; })) as Space;
- var space = RevitCore.UIApp.GetSelectedElement() as Space;
- if (space == null) return Result.Cancelled;
- SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
- options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center;
- var segments = space.GetBoundarySegments(options);
- double tolerance = RevitCore.App.ShortCurveTolerance;
- var allWalls = DocumentExtension.GetElements<Wall>(RevitCore.Doc);
- var tupleWalls = allWalls
- .Select(t => new Tuple<Curve, Wall>(ElementExtension.GetLocationCurve(t), t)).ToList();
- foreach (var segment in segments)
- {
- List<XYZ> xyzs = new List<XYZ>();
- List<XYZ> xyzs2 = new List<XYZ>();
- Stopwatch watch2 = new Stopwatch();
- watch2.Start();
- foreach (BoundarySegment boundarySegment in segment)
- {
- Stopwatch watch = new Stopwatch();
- watch.Start();
- var segmentElement = RevitCore.Doc.GetElement(boundarySegment.ElementId);
- if(segmentElement is Wall wall)
- {
- watch.Restart();
- var parallelWalls = GetParallelWalls(wall, tupleWalls);
- watch.Stop();
- Debug.WriteLine("Start:"+watch.Elapsed);
- watch.Restart();
- var segmentCurve = boundarySegment.GetCurve();
- var tessellates = segmentCurve.Tessellate();
- foreach (XYZ tessellate in tessellates)
- {
- xyzs2.Add(tessellate);
- var wallCurve = ElementExtension.GetLocationCurve(wall);
- var project = wallCurve.GetProjectPt(tessellate);
- var verticalVector = (project - tessellate).Normalize();
- var tempXyz = GetOuterXYZ(tessellate, verticalVector, segmentCurve, parallelWalls);
- if (tempXyz != null)
- xyzs.Add(tempXyz);
- }
- watch.Stop();
- Debug.WriteLine("End:"+watch.Elapsed);
- }
- else
- {
- foreach (XYZ tessellate in boundarySegment.GetCurve().Tessellate())
- {
- xyzs2.Add(tessellate);
- xyzs.Add(tessellate);
- }
- }
- }
- watch2.Stop();
- Debug.WriteLine(watch2.Elapsed);
- 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;
- }
- if (xyzs.Any())
- xyzs.Add(xyzs[0]);
- //画线-外墙
- for (int i = 0; i < xyzs.Count - 1; i++)
- {
- try
- {
- var p1 = xyzs[i];
- var p2 = xyzs[i + 1];
- if (p1.IsAlmostEqualTo(p2) || p1.DistanceTo(p2) < tolerance)
- continue;
- Curve curve = Line.CreateBound(p1, p2);
- RevitCore.DocCreater.NewDetailCurve(RevitCore.UIDoc.ActiveView, curve);
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- }
- }
- //if (xyzs2.Any())
- // xyzs2.Add(xyzs2[0]);
- ////画线-内墙
- //for (int i = 0; i < xyzs2.Count - 1; i++)
- //{
- // try
- // {
- // var p1 = xyzs2[i];
- // var p2 = xyzs2[i + 1];
- // if (p1.IsAlmostEqualTo(p2) || p1.DistanceTo(p2) < tolerance)
- // continue;
- // Curve curve = Line.CreateBound(p1, p2);
- // RevitCore.DocCreater.NewDetailCurve(RevitCore.UIDoc.ActiveView, curve);
- // }
- // catch (Exception e)
- // {
- // Console.WriteLine(e);
- // }
- //}
- }
- tran.Commit();
- }
- catch (Exception e)
- {
- tran.RollBack();
- throw;
- }
- }
- return Result.Succeeded;
- }
- private double m_RedundancySpace = 10d.ToApi();
- /// <summary>
- /// 获取平行墙,平行且投影有重叠部分
- /// </summary>
- /// <param name="wall"></param>
- /// <returns></returns>
- public List<Wall> GetParallelWalls(Wall wall,List<Tuple<Curve, Wall>> tupleWalls)
- {
- List<Wall> walls = new List<Wall>();
- walls.Add(wall);
- var curve = ElementExtension.GetLocationCurve(wall);
- var parallelWallTuples = tupleWalls.Where(t => t.Item1.IsParallel(curve));
- int len = walls.Count;
- do
- {
- len = walls.Count;
- foreach (Tuple<Curve, Wall> 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 = ElementExtension.GetLocationCurve(referenceWall);
- if(curve1.IsEqual(curve2))continue;
- 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 endP12 = CurveExtend.GetProjectPt(curve2, endP11);
- //没有重叠部分
- //if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2)
- // //|| startP22.IsOnCurve(curve1) ||endP22.IsOnCurve(curve1)
- // )
- //{
- // double width2 = referenceWall.Width;
- // double distacne = startP11.DistanceTo(endP11);
- // if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
- // walls.Add(parallelWall);
- //}
- }
- }
- } while (len != walls.Count);
- return walls;
- }
- /// <summary>
- /// 获取外廓后的点
- /// </summary>
- /// <param name="xyz">外廓点</param>
- /// <param name="verticalVector">外廓向量</param>
- /// <param name="segmentCurve">参考Curve</param>
- /// <param name="walls">平行墙集合</param>
- /// <returns></returns>
- public XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List<Wall> walls)
- {
- XYZ outerXyz = xyz;
- double distance = 0;
- foreach (Wall wall in walls)
- {
- /*
- * 注意幕墙,没有底面,直接取原始点xyz
- */
- List<PlanarFace> faces = GetBottomFaces(wall);
- 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);
- }
- /// <summary>
- /// 获取墙底面的轮廓,主要处理门窗分割墙问题
- /// </summary>
- /// <param name="wall"></param>
- /// <returns></returns>
- public List<PlanarFace> GetBottomFaces(Wall wall)
- {
- var solids = wall.GetSolids();
- double volume = double.MinValue;
- List<PlanarFace> faces = new List<PlanarFace>();
- foreach (var solid in solids)
- {
- var tempVolume = solid.Volume;
- double topZ = double.MaxValue;
- //取体积最大的Solid
- if (tempVolume.IsThan(volume))
- {
- volume = tempVolume;
- faces.Clear();
- }
- else
- {
- continue;
- }
- foreach (Face face in solid.Faces)
- {
- if (face is PlanarFace planarFace && planarFace.FaceNormal.IsEqual(-XYZ.BasisZ))
- {
- var tempZ = planarFace.Origin.Z;
- //取底面FaceNormal为(0,0,-1),Z最小
- if (tempZ.IsLess(topZ))
- {
- faces.Clear();
- topZ = tempZ;
- faces.Add(planarFace);
- }
- else if (tempZ.IsEqual(topZ))
- {
- faces.Add(planarFace);
- }
- }
- }
- }
- return faces;
- }
- }
- }
|