483 lines
18 KiB
C#
483 lines
18 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Autodesk.Revit.DB;
|
|
using Autodesk.Revit.DB.Mechanical;
|
|
using KDCS.Utils;
|
|
|
|
namespace KMBIM.Revit.Tools.Cmd.Hanger
|
|
{
|
|
class AutomaticHangerPlacement
|
|
{
|
|
private Document Document;
|
|
|
|
private List<MEPCurve> lstMEPCurve;
|
|
|
|
public XYZ StartPoint { get; set; }
|
|
|
|
public AutomaticHangerPlacement(Document doc, List<MEPCurve> lstMEPCurve)
|
|
{
|
|
this.Document = doc;
|
|
this.lstMEPCurve = lstMEPCurve;
|
|
}
|
|
|
|
public void a()
|
|
{
|
|
foreach (MEPCurve item in lstMEPCurve)
|
|
{
|
|
HangerSchema.g(item);
|
|
}
|
|
}
|
|
|
|
|
|
// 행거 자동 배치 실행
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="mainInstruction"></param>
|
|
/// <param name="InstallOption"></param>
|
|
/// <param name="ptStart">행거 배치 시작점</param>
|
|
/// <returns></returns>
|
|
public bool Place(ref string mainInstruction, InstallOption InstallOption, XYZ ptStart)
|
|
{
|
|
if (InstallOption == null)
|
|
{
|
|
return false;
|
|
}
|
|
StartPoint = ptStart; // 행거
|
|
|
|
a();
|
|
HangerSettings settings = HangerSettings.GetSettings();
|
|
Dictionary<Autodesk.Revit.DB.ElementId, MEPCurve> dictionary = new Dictionary<Autodesk.Revit.DB.ElementId, MEPCurve>();
|
|
foreach (MEPCurve item in lstMEPCurve)
|
|
{
|
|
dictionary[item.Id] = item;
|
|
}
|
|
List<List<MEPCurve>> list = new List<List<MEPCurve>>();
|
|
while (dictionary.Count > 0)
|
|
{
|
|
var enumerator2 = dictionary.GetEnumerator();
|
|
if (!enumerator2.MoveNext())
|
|
{
|
|
continue;
|
|
}
|
|
KeyValuePair<Autodesk.Revit.DB.ElementId, MEPCurve> current2 = enumerator2.Current;
|
|
List<MEPCurve> list2 = new List<MEPCurve>();
|
|
MEPCurve value = current2.Value;
|
|
list2.Add(value);
|
|
Line line = HangerSchema.GetLine(value);
|
|
if (line == null)
|
|
{
|
|
dictionary.Remove(current2.Key);
|
|
continue;
|
|
}
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
Autodesk.Revit.DB.XYZ A_2 = Util.GetEndPoint(line, i);
|
|
MEPCurve mEPCurve = a(value, ref A_2);
|
|
while (mEPCurve != null && dictionary.ContainsKey(mEPCurve.Id))
|
|
{
|
|
if (i == 0)
|
|
{
|
|
list2.Insert(0, mEPCurve);
|
|
}
|
|
else
|
|
{
|
|
list2.Add(mEPCurve);
|
|
}
|
|
dictionary.Remove(mEPCurve.Id);
|
|
mEPCurve = a(mEPCurve, ref A_2);
|
|
}
|
|
}
|
|
dictionary.Remove(current2.Key);
|
|
list.Add(list2);
|
|
}
|
|
Dictionary<MEPCurve, List<Autodesk.Revit.DB.XYZ>> listHangerPosition = new Dictionary<MEPCurve, List<Autodesk.Revit.DB.XYZ>>();
|
|
foreach (List<MEPCurve> item2 in list)
|
|
{
|
|
FindInstallationLocationForMEPCurve(InstallOption, item2, ref listHangerPosition);
|
|
}
|
|
View3DHanger newView3dHanger = new View3DHanger(this.Document);
|
|
Level anchorLevel = InstallOption.GetAnchorLevel();
|
|
if (anchorLevel != null) newView3dHanger.SetAncholLevel(anchorLevel);
|
|
foreach (KeyValuePair<MEPCurve, List<Autodesk.Revit.DB.XYZ>> item3 in listHangerPosition)
|
|
{
|
|
HangerFamily hangerFamily = new HangerFamily(InstallOption.GetAnchorLevel());
|
|
hangerFamily.SetKMBIMMEPCurveType(HangerSchema.GetMEPCurveType(item3.Key));
|
|
hangerFamily.SetView3dHanger(newView3dHanger);
|
|
Autodesk.Revit.DB.FamilySymbol familySymbol = InstallOption.GetFamilySymbol(item3.Key);
|
|
if (familySymbol == null)
|
|
{
|
|
continue;
|
|
}
|
|
hangerFamily.SetFamilySymbol(familySymbol);
|
|
if (!hangerFamily.getSize((Autodesk.Revit.DB.Element)item3.Key, settings))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (Autodesk.Revit.DB.XYZ item4 in item3.Value)
|
|
{
|
|
if (hangerFamily.GetElevation(item4, InstallOption.AnchorInstallBase))
|
|
{
|
|
HangerSchema.CreateFamilyInstance(this.Document, hangerFamily, InstallOption.AnchorInstallBase, ref mainInstruction);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// MEP곡선의 직경을 구한다.
|
|
public static double GetDiameter(MEPCurve curve)
|
|
{
|
|
KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType typeMEPCurve = HangerSchema.GetMEPCurveType(curve);
|
|
if (typeMEPCurve == KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.Conduit || // 전선관
|
|
typeMEPCurve == KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.Pipe || // 파이프
|
|
typeMEPCurve == KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.RoundDuct) // 원형덕트
|
|
{
|
|
return curve.Diameter; // 직경
|
|
}
|
|
// 각형인 경우 상당 직경을 구한다.
|
|
double w = curve.Width;
|
|
double h = curve.Height;
|
|
return 1.3 * Math.Pow(Math.Pow(w*h, 5.0) / Math.Pow(w+h, 2.0), 1.0 / 8.0) ; // 각형 크기의 상당직경
|
|
}
|
|
|
|
private void AddHangerLocation(MEPCurve mepcurve, Autodesk.Revit.DB.XYZ pt, ref Dictionary<MEPCurve, List<Autodesk.Revit.DB.XYZ>> dictLocation)
|
|
{
|
|
if (!dictLocation.ContainsKey(mepcurve))
|
|
{
|
|
dictLocation[mepcurve] = new List<Autodesk.Revit.DB.XYZ>();
|
|
}
|
|
dictLocation[mepcurve].Add(pt);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 주어진 MEP커브에 설정한 옵션에 따라 행거 설치 위치를 찾습니다.
|
|
/// </summary>
|
|
/// <param name="InstallOption">설치 옵션</param>
|
|
/// <param name="listMEPCurve">MEP곡선</param>
|
|
/// <param name="dictMEPCurveHangerLocation">MEP곡선의 설치 위치</param>
|
|
private void FindInstallationLocationForMEPCurve(InstallOption InstallOption, List<MEPCurve> listMEPCurve, ref Dictionary<MEPCurve, List<Autodesk.Revit.DB.XYZ>> dictMEPCurveHangerLocation)
|
|
{
|
|
if (listMEPCurve == null || listMEPCurve.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
List<double> list = new List<double>();
|
|
for (int i = 0; i < listMEPCurve.Count; i++)
|
|
{
|
|
list.Add(GetDiameter(listMEPCurve[i]));
|
|
}
|
|
|
|
double dblMinMargin = 0.82021; // 250mm = 0.82021 ft
|
|
double Installation_spacing = -1d;
|
|
Autodesk.Revit.DB.XYZ ep = StartPoint;
|
|
Autodesk.Revit.DB.XYZ dirLocation = null;
|
|
bool flag = false;
|
|
for (int j = 0; j < listMEPCurve.Count; j++)
|
|
{
|
|
UnitInstallOption uiOption = InstallOption.Options[0]; //.GetRule(listMEPCurve[j]);
|
|
if (uiOption == null)
|
|
{
|
|
continue;
|
|
}
|
|
Line line = HangerSchema.GetLine(listMEPCurve[j]);
|
|
Autodesk.Revit.DB.XYZ ptNext = null;
|
|
double dst;
|
|
if (Util.GT_ET(Installation_spacing, 0.0))
|
|
{
|
|
flag = false;
|
|
Installation_spacing = uiOption.OffsetFromEnd;
|
|
if (Util.GT_ET(Installation_spacing, 0.0))
|
|
{
|
|
continue;
|
|
}
|
|
if (j == 0 && listMEPCurve.Count > 1)
|
|
{
|
|
Autodesk.Revit.DB.XYZ sp = Util.GetEndPoint(HangerSchema.GetLine(listMEPCurve[1]), 0);
|
|
int inxSp = GetLineIndex(line, sp);
|
|
ep = Util.GetEndPoint(line, 1 - inxSp);
|
|
|
|
dirLocation = ((inxSp == 0) ? line.Direction.Multiply(-1.0) : line.Direction);
|
|
}
|
|
else
|
|
{
|
|
int inxEp = GetLineIndex(line, ep);
|
|
ep = Util.GetEndPoint(line, inxEp);
|
|
dirLocation = ((inxEp == 1) ? line.Direction.Multiply(-1.0) : line.Direction);
|
|
}
|
|
|
|
if (ptNext == null)
|
|
{
|
|
|
|
ptNext = line.Project(StartPoint).XYZPoint;
|
|
int inxEp = GetLineIndex(line, ptNext);
|
|
ep = Util.GetEndPoint(line, inxEp);
|
|
|
|
}
|
|
else ptNext = ep.Add(dirLocation.Multiply(Installation_spacing));
|
|
dst = line.Distance(ptNext);
|
|
|
|
if (!Util.fuzzyEqual(dst, 0.0))
|
|
{
|
|
Installation_spacing = uiOption.HangerSpacing;
|
|
continue;
|
|
}
|
|
|
|
AddHangerLocation(listMEPCurve[j], ptNext, ref dictMEPCurveHangerLocation);
|
|
Installation_spacing = uiOption.HangerSpacing;
|
|
if (Util.GT_ET(Installation_spacing, 0.0))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flag = true;
|
|
}
|
|
|
|
|
|
ep = ptNext;
|
|
ptNext = ptNext.Add(dirLocation.Multiply(Installation_spacing));
|
|
dst = line.Distance(ptNext);
|
|
if (flag && !Util.fuzzyEqual(dst, 0.0))
|
|
{
|
|
int inxEP = GetLineIndex(line, ep);
|
|
ep = Util.GetEndPoint(line, inxEP);
|
|
ptNext = ep.Add(dirLocation.Multiply(uiOption.OffsetFromEnd));
|
|
dst = line.Distance(ptNext);
|
|
|
|
}
|
|
|
|
|
|
XYZ tmpNext = ptNext;
|
|
// 배치 가능한 위치가 아닌 경우 위치를 조정한다.
|
|
bool bAdjust = false;
|
|
var p1 = line.GetEndPoint(0);
|
|
var p2 = line.GetEndPoint(1);
|
|
if (dst < dblMinMargin)
|
|
{
|
|
XYZ vDir = null;
|
|
if (ptNext.DistanceTo(p1) < ptNext.DistanceTo(p2))
|
|
{
|
|
vDir = (p1 - ptNext).Normalize();
|
|
ep = p1;
|
|
}
|
|
else
|
|
{
|
|
vDir = (p2 - ptNext).Normalize();
|
|
ep = p2;
|
|
}
|
|
|
|
if (vDir.IsAlmostEqualTo(dirLocation)==false)
|
|
{
|
|
// 아래 줄때문에 시작점에서 다음 점의 간격이 항상 50mm 더 적다.
|
|
//ptNext = ptNext.Subtract(dirLocation.Multiply(dst + 0.164042)); // 0.164042 feet = 50mm
|
|
dst = 0;
|
|
}
|
|
}
|
|
|
|
|
|
while (Util.fuzzyEqual(dst, 0.0))
|
|
{
|
|
ep = ptNext;
|
|
AddHangerLocation(listMEPCurve[j], ptNext, ref dictMEPCurveHangerLocation);
|
|
ptNext = ptNext.Add(dirLocation.Multiply(Installation_spacing));
|
|
|
|
dst = line.Distance(ptNext);
|
|
}
|
|
|
|
|
|
if (j == listMEPCurve.Count - 1 || (j + 1 < listMEPCurve.Count && !Util.fuzzyEqual(list[j], list[j + 1])))
|
|
{
|
|
Installation_spacing = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
private int GetLineIndex(Line line, Autodesk.Revit.DB.XYZ pt)
|
|
{
|
|
if (pt == null)
|
|
{
|
|
return 0;
|
|
}
|
|
Autodesk.Revit.DB.XYZ sp = Util.GetEndPoint(line, 0);
|
|
Autodesk.Revit.DB.XYZ ep = Util.GetEndPoint(line, 1);
|
|
if (sp.DistanceTo(pt) < ep.DistanceTo(pt))
|
|
{
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
protected MEPCurve a(MEPCurve A_0, ref Autodesk.Revit.DB.XYZ A_1)
|
|
{
|
|
if (A_0.ConnectorManager == null)
|
|
{
|
|
return null;
|
|
}
|
|
Line line = HangerSchema.GetLine(A_0);
|
|
if (line == null)
|
|
{
|
|
return null;
|
|
}
|
|
HashSet<Autodesk.Revit.DB.ElementId> hashSet = new HashSet<Autodesk.Revit.DB.ElementId>();
|
|
hashSet.Add(A_0.Id);
|
|
foreach (Autodesk.Revit.DB.Element item in a(A_0.ConnectorManager, A_1, hashSet))
|
|
{
|
|
Autodesk.Revit.DB.ConnectorManager connectorManager = a(item);
|
|
if (connectorManager == null)
|
|
{
|
|
continue;
|
|
}
|
|
hashSet.Add(item.Id);
|
|
List<Autodesk.Revit.DB.Element> list = a(connectorManager, null, hashSet);
|
|
while (list.Count > 0)
|
|
{
|
|
Autodesk.Revit.DB.Element element = list[0];
|
|
hashSet.Add(element.Id);
|
|
if (HangerSchema.e(element))
|
|
{
|
|
Line line2 = HangerSchema.GetLine(element as MEPCurve);
|
|
if (line.Direction.CrossProduct(line2.Direction).IsAlmostEqualTo(Autodesk.Revit.DB.XYZ.Zero) && line.Origin.Subtract(line2.Origin).CrossProduct(line.Direction).IsAlmostEqualTo(Autodesk.Revit.DB.XYZ.Zero))
|
|
{
|
|
Autodesk.Revit.DB.XYZ xYZ = Util.GetEndPoint(line2, 0);
|
|
Autodesk.Revit.DB.XYZ xYZ2 = Util.GetEndPoint(line2, 1);
|
|
if (xYZ.DistanceTo(A_1) < xYZ2.DistanceTo(A_1))
|
|
{
|
|
A_1 = xYZ2;
|
|
}
|
|
else
|
|
{
|
|
A_1 = xYZ;
|
|
}
|
|
return element as MEPCurve;
|
|
}
|
|
}
|
|
else if (element is Autodesk.Revit.DB.FamilyInstance)
|
|
{
|
|
connectorManager = a(element);
|
|
if (connectorManager != null)
|
|
{
|
|
list.AddRange(a(connectorManager, null, hashSet));
|
|
}
|
|
}
|
|
list.RemoveAt(0);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private Autodesk.Revit.DB.ConnectorManager a(Autodesk.Revit.DB.Element A_0)
|
|
{
|
|
if (!(A_0 is Autodesk.Revit.DB.FamilyInstance))
|
|
{
|
|
return null;
|
|
}
|
|
Autodesk.Revit.DB.FamilyInstance familyInstance = A_0 as Autodesk.Revit.DB.FamilyInstance;
|
|
if (familyInstance.MEPModel == null || !(familyInstance.MEPModel is MechanicalFitting))
|
|
{
|
|
return null;
|
|
}
|
|
return familyInstance.MEPModel.ConnectorManager;
|
|
}
|
|
|
|
private List<Autodesk.Revit.DB.Connector> a(Autodesk.Revit.DB.ConnectorManager A_0)
|
|
{
|
|
List<Autodesk.Revit.DB.Connector> list = new List<Autodesk.Revit.DB.Connector>();
|
|
if (A_0 != null)
|
|
{
|
|
foreach (Autodesk.Revit.DB.Connector connector in A_0.Connectors)
|
|
{
|
|
if ((connector.ConnectorType & Autodesk.Revit.DB.ConnectorType.Physical) != 0)
|
|
{
|
|
list.Add(connector);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private List<Autodesk.Revit.DB.Connector> a(Autodesk.Revit.DB.Connector A_0)
|
|
{
|
|
List<Autodesk.Revit.DB.Connector> list = new List<Autodesk.Revit.DB.Connector>();
|
|
if (A_0 != null)
|
|
{
|
|
foreach (Autodesk.Revit.DB.Connector allRef in A_0.AllRefs)
|
|
{
|
|
if ((allRef.ConnectorType & Autodesk.Revit.DB.ConnectorType.Physical) != 0)
|
|
{
|
|
list.Add(allRef);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
protected List<Autodesk.Revit.DB.Element> a(Autodesk.Revit.DB.ConnectorManager A_0, Autodesk.Revit.DB.XYZ A_1, HashSet<Autodesk.Revit.DB.ElementId> A_2)
|
|
{
|
|
Autodesk.Revit.DB.ElementId elementId = Autodesk.Revit.DB.ElementId.InvalidElementId;
|
|
List<Autodesk.Revit.DB.Element> list = new List<Autodesk.Revit.DB.Element>();
|
|
foreach (Autodesk.Revit.DB.Connector item in a(A_0))
|
|
{
|
|
if (A_1 != null && !item.Origin.IsAlmostEqualTo(A_1))
|
|
{
|
|
continue;
|
|
}
|
|
if (elementId == Autodesk.Revit.DB.ElementId.InvalidElementId && item.Owner != null)
|
|
{
|
|
elementId = item.Owner.Id;
|
|
}
|
|
foreach (Autodesk.Revit.DB.Connector item2 in a(item))
|
|
{
|
|
if (item2.Owner != null && item2.Owner.Id != elementId && (A_2 == null || !A_2.Contains(item2.Owner.Id)))
|
|
{
|
|
list.Add(item2.Owner);
|
|
}
|
|
}
|
|
if (A_1 != null)
|
|
{
|
|
return list;
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
protected bool a(MEPCurve A_0, double A_1, ref List<Autodesk.Revit.DB.XYZ> A_2)
|
|
{
|
|
Line line = HangerSchema.GetLine(A_0);
|
|
if (line == null || line.ApproximateLength < A_1 + 0.001)
|
|
{
|
|
return false;
|
|
}
|
|
A_2 = new List<Autodesk.Revit.DB.XYZ>();
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
Autodesk.Revit.DB.XYZ item = Util.GetEndPoint(line, i);
|
|
if (i == 0)
|
|
{
|
|
item += line.Direction.Multiply(A_1);
|
|
}
|
|
else
|
|
{
|
|
item -= line.Direction.Multiply(A_1);
|
|
}
|
|
A_2.Add(item);
|
|
if (line.ApproximateLength < 2.0 * A_1 + 0.001)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|
|
}
|