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 lstMEPCurve; public XYZ StartPoint { get; set; } public AutomaticHangerPlacement(Document doc, List lstMEPCurve) { this.Document = doc; this.lstMEPCurve = lstMEPCurve; } public void a() { foreach (MEPCurve item in lstMEPCurve) { HangerSchema.g(item); } } // 행거 자동 배치 실행 /// /// /// /// /// /// 행거 배치 시작점 /// public bool Place(ref string mainInstruction, InstallOption InstallOption, XYZ ptStart) { if (InstallOption == null) { return false; } StartPoint = ptStart; // 행거 a(); HangerSettings settings = HangerSettings.GetSettings(); Dictionary dictionary = new Dictionary(); foreach (MEPCurve item in lstMEPCurve) { dictionary[item.Id] = item; } List> list = new List>(); while (dictionary.Count > 0) { var enumerator2 = dictionary.GetEnumerator(); if (!enumerator2.MoveNext()) { continue; } KeyValuePair current2 = enumerator2.Current; List list2 = new List(); 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> listHangerPosition = new Dictionary>(); foreach (List 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> 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> dictLocation) { if (!dictLocation.ContainsKey(mepcurve)) { dictLocation[mepcurve] = new List(); } dictLocation[mepcurve].Add(pt); } /// /// 주어진 MEP커브에 설정한 옵션에 따라 행거 설치 위치를 찾습니다. /// /// 설치 옵션 /// MEP곡선 /// MEP곡선의 설치 위치 private void FindInstallationLocationForMEPCurve(InstallOption InstallOption, List listMEPCurve, ref Dictionary> dictMEPCurveHangerLocation) { if (listMEPCurve == null || listMEPCurve.Count == 0) { return; } List list = new List(); 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 hashSet = new HashSet(); 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 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 a(Autodesk.Revit.DB.ConnectorManager A_0) { List list = new List(); 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 a(Autodesk.Revit.DB.Connector A_0) { List list = new List(); 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 a(Autodesk.Revit.DB.ConnectorManager A_0, Autodesk.Revit.DB.XYZ A_1, HashSet A_2) { Autodesk.Revit.DB.ElementId elementId = Autodesk.Revit.DB.ElementId.InvalidElementId; List list = new List(); 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 A_2) { Line line = HangerSchema.GetLine(A_0); if (line == null || line.ApproximateLength < A_1 + 0.001) { return false; } A_2 = new List(); 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; } } }