Client/Desktop/KMBIM3.0/KMBIM3.0_23.08.16_수정최종/Cmd/Hanger/HangerAutoPlace.cs

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;
}
}
}