using System; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using System.Collections.Generic; using System.Windows.Forms; using System.Linq; using Autodesk.Revit.UI.Selection; using Autodesk.Revit.DB.Plumbing; using KDCS.Utils; using Autodesk.Revit.DB.Structure; using KMBIM.Revit.Tools.Cmd.SprinklerConnect; using KMBIM.Revit.Tools; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] class Sprinkler_Downward_Auto : IExternalCommand { UIApplication uiapp; UIDocument uidoc; Autodesk.Revit.DB.Document doc; Autodesk.Revit.Creation.Application creApp; Autodesk.Revit.Creation.Document creDoc; Autodesk.Revit.UI.ExternalCommandData m_commandData; double m_MainHgt = 0, m_BranchHgt = 0, m_HeadOffset = 0, m_ConnectDist = 0, m_CapDist = 0, GenLevElevation = 0, m_Tolerance = 0, m_TReducerDist = 0; int m_Mode = 0; List lst_objSprinkler = new List(); ObjComparer OC = new ObjComparer(); ObjOrthoComparer OrthoC = new ObjOrthoComparer(); XYZ mainSp = null, mainEp = null; SprinKler_Function Spkr_Func = new SprinKler_Function(); //이격 방향 XYZ SeparationVec = null; Pipe MainPipe=null; Line pipeline = null;//메인 배관 선형 public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded; m_commandData = commandData; uiapp = commandData.Application; uidoc = uiapp.ActiveUIDocument; doc = uidoc.Document; creApp = uiapp.Application.Create; creDoc = doc.Create; List m_SpklrList = new List(); List> m_TotalObjLst = new List>(); List> Left_TotalObjLst = new List>(); List> Right_TotalObjLst = new List>(); List m_SpklrHgtLst = new List(); try { Reference pickref = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new SelectionMainPipe(), "교차배관 선택 : "); if (pickref == null) return Result.Cancelled; IList pickrefs = commandData.Application.ActiveUIDocument.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, new HeaderFilter(), "배관에 연결할 스프링클러 범위 지정 : "); if (pickrefs == null) return Result.Cancelled; ElementId id = pickref.ElementId; Element elem1 = doc.GetElement(id) as Element; foreach (Reference refer in pickrefs) { ElementId id2 = refer.ElementId; Element elem2 = doc.GetElement(id2); m_SpklrList.Add(id2); } //메인 파이프 간격띄우기 구하기 if (elem1 is Pipe) { MainPipe = elem1 as Pipe; pipeline = (MainPipe.Location as LocationCurve).Curve as Line; //m_MainHgt = pipeline.GetEndPoint(0).Z; m_MainHgt = MainPipe.LevelOffset; //현재 레벨의 높이 구하기.(active Level을 구하면 3D에서 작도가 안됌.) GenLevElevation = Unit.FeetToMM(pipeline.GetEndPoint(0).Z - MainPipe.LevelOffset); mainSp = pipeline.GetEndPoint(0); mainEp = pipeline.GetEndPoint(1); //SprinKler_Function 변수값 넘겨주기 Spkr_Func.doc = uidoc.Document; Spkr_Func.creDoc = doc.Create; Spkr_Func.uiapp = commandData.Application; Spkr_Func.MainPipeTypeId = MainPipe.PipeType.Id; Spkr_Func.MainSystemTypeId = MainPipe.MEPSystem.GetTypeId(); Spkr_Func.MainLevelId = MainPipe.ReferenceLevel.Id; } //기준 헤드 지정 Reference pickDirRef = commandData.Application.ActiveUIDocument.Selection.PickObject(ObjectType.Element, new HeaderFilter(), "기준 스프링클러 헤드 선택 : "); if (pickDirRef == null) return Result.Cancelled; Element pickDirElem = doc.GetElement(pickDirRef.ElementId); //이격 거리 방향 지정 XYZ SeparatePt = commandData.Application.ActiveUIDocument.Selection.PickPoint("가지배관 방향 지정 : "); if (SeparatePt == null) return Result.Cancelled; List DirHeadCons = Util.GetElementConnectors(pickDirElem); IntersectionResult interRes = pipeline.Project(DirHeadCons.First().Origin); XYZ interZ0 = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, 0); XYZ HeadZ0 = new XYZ(DirHeadCons.First().Origin.X, DirHeadCons.First().Origin.Y, 0); XYZ SeparatePtZ0 = new XYZ(SeparatePt.X, SeparatePt.Y, 0); SeparationVec = (interZ0 - HeadZ0).Normalize(); bool isRight = Util.isRightPoint(SeparatePtZ0, HeadZ0, interZ0); if (isRight == true) SeparationVec = Util.RotateVector(SeparationVec, Util.DTR(-90.0)); else SeparationVec = Util.RotateVector(SeparationVec, Util.DTR(90.0)); //대화상자 기본값 설정 Form_Downward dlg = new Form_Downward(); dlg.MainHeight = Math.Round(Unit.FeetToMM(m_MainHgt), 3); dlg.BranchHeight = Math.Round(Unit.FeetToMM(m_MainHgt), 3) + 300; dlg.HeaderOffset = 150; dlg.ConnectDist = 150; dlg.CapDist = 100; dlg.SpkrTol = 5; dlg.TeeReducerDist = 100; //플렉시블 파이프 유형 로드 유무 ICollection FlexPipeTypeLst = new FilteredElementCollector(doc).OfClass(typeof(FlexPipeType)).ToElements(); if (FlexPipeTypeLst.Count() > 0) dlg.m_FlexPipeLoad = true; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.Cancel) return Result.Succeeded; //대화상자 값 가져오기 m_MainHgt = dlg.MainHeight; m_BranchHgt = dlg.BranchHeight; m_HeadOffset = dlg.HeaderOffset; m_ConnectDist = dlg.ConnectDist; m_CapDist = dlg.CapDist; m_Mode = dlg.m_RadIdx; m_Tolerance = dlg.SpkrTol; m_TReducerDist = dlg.TeeReducerDist; //교차배관, 가지배관 높이 재지정 m_MainHgt = m_MainHgt + GenLevElevation; m_BranchHgt = m_BranchHgt + GenLevElevation; //헤드 값 지정 foreach (ElementId elemid in m_SpklrList) { FamilyInstance family = (doc.GetElement(elemid)) as FamilyInstance; ConnectorSet conSet = family.MEPModel.ConnectorManager.Connectors; foreach (Connector con in conSet) { interRes = pipeline.Project(con.Origin); XYZ interpt = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, con.Origin.Z); ObjSprinKler objSprinKler = new ObjSprinKler(); objSprinKler.HeadCon = con; objSprinKler.m_Headpt = con.Origin; objSprinKler.m_InterPt = interpt; objSprinKler.m_SpID = con.Owner.Id; objSprinKler.m_Ep2InterDst = interRes.XYZPoint.DistanceTo(pipeline.GetEndPoint(1)); XYZ SepaPt = Util.Polar(con.Origin, SeparationVec, Unit.MMToFeet(m_ConnectDist)); //이격점에서 메인 교차점 interRes = pipeline.Project(SepaPt); interpt = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, SepaPt.Z); //이격점, 이격점에 따른 교차점 저장 objSprinKler.m_InterPt = interpt; objSprinKler.SeparateionPt = SepaPt; //헤드 정보 리스트에 담기 lst_objSprinkler.Add(objSprinKler); m_SpklrHgtLst.Add(con.Origin.Z); break; } } //헤드 수직점에 따른 헤드 값 정렬 lst_objSprinkler.Sort(OC); foreach (ObjSprinKler obj in lst_objSprinkler) { //Util.Pyosi(doc, obj.m_InterPt, 1); //MessageBox.Show("1"); } bool loop = true; //헤드를 거리별로 그룹 나눠서 리스트에 저장하기. while (loop) { if (lst_objSprinkler.Count <= 0) break; List Group = Spkr_Func.DivideObjSprinKlerData(MainPipe, lst_objSprinkler); //추출 그룹 정렬 Group.Sort(OrthoC); List ContainLst = new List(); foreach (ObjSprinKler obj in Group) { //int idx = lst_objSprinkler.IndexOf(obj); //lst_objSprinkler.RemoveAt(idx); lst_objSprinkler.Remove(obj); } //나눈 그룹 리스트에 담기. if (Group.Count > 0) m_TotalObjLst.Add(Group); }//while end //총 리스트에서 헤드가 1개일 때 그 헤드 리스트 앞 뒤 중 가까운쪽에 넣고 삭제 m_TotalObjLst = Spkr_Func.RemoveSingleObjLst(m_TotalObjLst); //처음 관경25는 헤드쪽때문에 기입 List headLst = new List(); headLst.Add(25); headLst.Add(25); headLst.Add(25); headLst.Add(32); headLst.Add(40); headLst.Add(40); headLst.Add(50); headLst.Add(50); headLst.Add(50); headLst.Add(50); headLst.Add(50); headLst.Add(65); headLst.Add(65); headLst.Add(65); headLst.Add(65); headLst.Add(65); headLst.Add(65); headLst.Add(65); List TeeBranchPipeLst = new List(); using (Transaction trans1 = new Transaction(doc)) { trans1.Start("cre"); //총 리스트를 메인관 기준 왼쪽 오른쪽 분류 foreach (List lst_obj in m_TotalObjLst) { //허용오차 범위 안 스프링클러 정렬 List sortLst_obj = SprinklerTolSort(lst_obj, pipeline, m_Tolerance); doc.Regenerate(); List lst_LeftObj = new List(); List lst_RightObj = new List(); foreach (ObjSprinKler obj in sortLst_obj) { if (Util.isRightPoint(obj.m_Headpt, mainEp, mainSp)) lst_RightObj.Add(obj); else lst_LeftObj.Add(obj); } List pipeLst = ProcessingSpkr(lst_LeftObj, lst_RightObj, elem1, headLst, m_Mode); TeeBranchPipeLst.AddRange(pipeLst); } ElementId MainPipeID = elem1.Id; //메인관에 T연결 foreach (Pipe pp in TeeBranchPipeLst) { Connector pipeSpCon = null, pipeEpCon = null; bool b_Cons = Util.GetStartEndConnector(pp, ref pipeSpCon, ref pipeEpCon); if (b_Cons == false) continue; Line MainLine = ((doc.GetElement(MainPipeID) as Pipe).Location as LocationCurve).Curve as Line; XYZ DivPt = Util.GetPointOnLine(MainLine, pipeEpCon.Origin); ElementId divID = PlumbingUtils.BreakCurve(doc, MainPipeID, DivPt); if (divID == null) continue; Connector MainCon1 = null, MainCon2 = null; List MainCon1Lst = Util.GetElementConnectors(doc.GetElement(divID)); List MainCon2Lst = Util.GetElementConnectors(doc.GetElement(MainPipeID)); foreach (Connector con1 in MainCon1Lst) { foreach (Connector con2 in MainCon2Lst) { if (con1.Origin.IsAlmostEqualTo(con2.Origin, Unit.MMToFeet(0.01))) { MainCon1 = con1; MainCon2 = con2; } } } Util.CreateTee(creDoc, MainCon1, MainCon2, pipeEpCon); MainPipeID = divID; } trans1.Commit(); } } catch (Exception e) { //MessageBox.Show("" + e); } return Result.Succeeded; } // 헤드와 연결될 배관 종류// 0 = 배관 / 1 = 플렉시블 배관 public List ProcessingSpkr(List RangeLeftLst, List RangeRightLst, Element MainElem, List HeadDiaLst, int Mode) { ObjSprinKler obj1 = null, obj2 = null; List m_LeftPtLst = new List(); List m_RightPtLst = new List(); List m_LCurveLst = new List(); List m_RCurveLst = new List(); List newPipes = new List(); List TeeBranchPipeLst = new List(); List ExceptSpkrLst = new List(); Element LeftLastElem = null; Element RightLastElem = null; bool b_leftLst_Connect = false; bool b_rightLst_Connect = false; foreach (ObjSprinKler obj in RangeLeftLst) { if (obj.HeadCon.IsConnected == true) { b_leftLst_Connect = true; break; } } foreach (ObjSprinKler obj in RangeRightLst) { if (obj.HeadCon.IsConnected == true) { b_rightLst_Connect = true; break; } } if (b_leftLst_Connect == true || b_rightLst_Connect == true) return TeeBranchPipeLst; //메인관 기준 왼쪽 int sp_hd = 0, sp_In = 0; bool b_LeftDraw = true; if (RangeLeftLst.Count() > 0) { //가지파이프 for (int i = 0; i < RangeLeftLst.Count(); i++) { if (i < (RangeLeftLst.Count() - 1)) { obj1 = RangeLeftLst[i]; obj2 = RangeLeftLst[i + 1]; List mainPts = Spkr_Func.DownSPJOIN(obj1, obj2, m_BranchHgt, ref sp_In, i + 1, HeadDiaLst); //틀어진 점에서 작도할 거리가 나오지 않으면 작도 X if (mainPts == null) { if (RangeLeftLst.Count() - 1 >= i + 2) { mainPts = Spkr_Func.DownSPJOIN(obj1, RangeLeftLst[i + 2], m_BranchHgt, ref sp_In, i + 1, HeadDiaLst); if (mainPts.Count() > 0) { m_LeftPtLst.AddRange(mainPts); } i++; } ExceptSpkrLst.Add(obj2); } else if (mainPts.Count() > 0) { m_LeftPtLst.AddRange(mainPts); } } } if (b_LeftDraw == true) { //작도할 수 없는 스프링클러 제거 foreach (ObjSprinKler obj in ExceptSpkrLst) { RangeLeftLst.Remove(obj); } //메인 연결될 가지파이프 XYZ lastPt = Spkr_Func.DownGetMain2LastpipePoint(RangeLeftLst.Last(), m_BranchHgt); m_LeftPtLst.Add(lastPt); //Util.Pyosi(doc, lastPt, 0); m_LeftPtLst.Reverse(); //캡 파이프 XYZ capPt = Spkr_Func.DownGetCAPpoint(RangeLeftLst.First(), m_BranchHgt, m_CapDist); m_LeftPtLst.Add(capPt); m_LeftPtLst.Reverse(); //파이프 및 엘보 생성 newPipes = Util.CreatePipe(uiapp, doc, m_LeftPtLst, Spkr_Func.MainSystemTypeId, Spkr_Func.MainPipeTypeId, Spkr_Func.MainLevelId); //헤드와 가지관 연결 List LeftElemIdLst = Spkr_Func.DownConnectHead2pipe(RangeLeftLst, newPipes, HeadDiaLst, m_HeadOffset, m_ConnectDist, m_BranchHgt, m_TReducerDist, Mode); doc.Regenerate(); Spkr_Func.ApplyReducer(LeftElemIdLst, 100); LeftLastElem = doc.GetElement(LeftElemIdLst.Last()); } } //메인관 기준 오른쪽 sp_hd = 0; sp_In = 0; bool b_RightDraw = true; ExceptSpkrLst.Clear(); if (RangeRightLst.Count() > 0) { ////캡 파이프 //List capPt = GetCAPpipe(RangeRightLst.First(), m_HeadOffset, m_CapDist); //m_RightPtLst.AddRange(capPt); //가지 파이프 for (int i = 0; i < RangeRightLst.Count(); i++) { if (i < (RangeRightLst.Count() - 1)) { obj1 = RangeRightLst[i]; obj2 = RangeRightLst[i + 1]; List mainPts = Spkr_Func.DownSPJOIN(obj1, obj2, m_BranchHgt, ref sp_In, i + 1, HeadDiaLst); //foreach (XYZ pt in mainPts) //{ // Util.Pyosi(doc, pt, 0); //} //틀어진 점에서 작도할 거리가 나오지 않으면 작도 X if (mainPts == null) { if (RangeRightLst.Count() - 1 >= i + 2) { mainPts = Spkr_Func.DownSPJOIN(obj1, RangeRightLst[i + 2], m_BranchHgt, ref sp_In, i + 1, HeadDiaLst); if (mainPts.Count() > 0) { m_RightPtLst.AddRange(mainPts); } i++; } ExceptSpkrLst.Add(obj2); } else if (mainPts.Count() > 0) { m_RightPtLst.AddRange(mainPts); } } } if (b_RightDraw == true) { //작도할 수 없는 스프링클러 제거 foreach (ObjSprinKler obj in ExceptSpkrLst) { RangeRightLst.Remove(obj); } //메인 연결될 가지파이프 XYZ lastPt = Spkr_Func.DownGetMain2LastpipePoint(RangeRightLst.Last(), m_BranchHgt); m_RightPtLst.Add(lastPt); m_RightPtLst.Reverse(); //캡 파이프 XYZ capPt = Spkr_Func.DownGetCAPpoint(RangeRightLst.First(), m_BranchHgt, m_CapDist); m_RightPtLst.Add(capPt); m_RightPtLst.Reverse(); //파이프 및 엘보 생성 newPipes = Util.CreatePipe(uiapp, doc, m_RightPtLst, Spkr_Func.MainSystemTypeId, Spkr_Func.MainPipeTypeId, Spkr_Func.MainLevelId); //헤드와 가지관 연결 List RightElemIdLst = Spkr_Func.DownConnectHead2pipe(RangeRightLst, newPipes, HeadDiaLst, m_HeadOffset, m_ConnectDist, m_BranchHgt, m_TReducerDist, Mode); doc.Regenerate(); Spkr_Func.ApplyReducer(RightElemIdLst, 100); RightLastElem = doc.GetElement(RightElemIdLst.Last()); } } //메인관 가지관 연결 TeeBranchPipeLst = Spkr_Func.MainConnectBranch(MainElem, LeftLastElem, RightLastElem); //trans1.Commit(); return TeeBranchPipeLst; } public List SprinklerTolSort(List GroupSpkr, Line MainLine, double m_Tol) { List resLst = new List(); ObjSprinKler FirstSpkr = GroupSpkr.First(); XYZ newEpt = new XYZ(MainLine.GetEndPoint(1).X, MainLine.GetEndPoint(1).Y, FirstSpkr.m_InterPt.Z); //double firstDist = FirstSpkr.m_InterPt.DistanceTo(newEpt); foreach (ObjSprinKler spkr in GroupSpkr) { if (spkr.m_SpID.Equals(FirstSpkr.m_SpID)) { resLst.Add(spkr); continue; } double nextDist = spkr.m_InterPt.DistanceTo(newEpt); if (FirstSpkr.m_InterPt.DistanceTo(spkr.m_InterPt) > Unit.MMToFeet(m_Tol) || FirstSpkr.m_InterPt.DistanceTo(spkr.m_InterPt) < Unit.MMToFeet(0.01)) { resLst.Add(spkr); continue; } XYZ moveVec = (FirstSpkr.m_InterPt - spkr.m_InterPt).Normalize(); XYZ movePt = Util.Polar(spkr.m_Headpt, moveVec, FirstSpkr.m_InterPt.DistanceTo(spkr.m_InterPt)); FamilyInstance family = doc.GetElement(spkr.m_SpID) as FamilyInstance; LocationPoint locpt = family.Location as LocationPoint; locpt.Point = movePt; doc.Regenerate(); List spkrCon = Util.GetElementConnectors(family); //Util.Pyosi(doc, spkrCon.First().Origin, 0); //메인관-커넥터 가까운 점 IntersectionResult interRes = MainLine.Project(spkrCon.First().Origin); XYZ interPt = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, spkrCon.First().Origin.Z); XYZ SepaPt = Util.Polar(spkrCon.First().Origin, SeparationVec, Unit.MMToFeet(m_ConnectDist)); //스프링클러 헤드 정보 spkr.HeadCon = spkrCon.First(); spkr.m_Headpt = spkrCon.First().Origin; spkr.m_Ep2InterDst = interRes.XYZPoint.DistanceTo(pipeline.GetEndPoint(1)); spkr.m_SpID = family.Id; spkr.SeparateionPt = SepaPt; //이격점에서 메인 교차점 interRes = pipeline.Project(SepaPt); interPt = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, SepaPt.Z); spkr.m_InterPt = interPt; resLst.Add(spkr); } return resLst; } public class SelectionMainPipe : ISelectionFilter { public bool AllowElement(Element element) { if (element.Category == null) return false; if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves) { return true; } return false; } public bool AllowReference(Reference refer, XYZ point) { return false; } } public class HeaderFilter : ISelectionFilter { public bool AllowElement(Element element) { if (element.Category == null) return false; if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Sprinklers) { return true; } return false; } public bool AllowReference(Reference refer, XYZ point) { return false; } } } }