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 SpinKler; 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_Upword_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_CapDist = 0, m_GenLevElevation = 0, m_Tolerance = 0, m_TReducerDist = 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(); Pipe MainPipe = 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(); double m_MainAng = 0; try { Reference pickref = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new SelectionFilter(), "교차배관 선택 : "); if (pickref == null) return Result.Succeeded; IList pickrefs = commandData.Application.ActiveUIDocument.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, new HeaderFilter(), "배관에 연결할 스프링클러 범위 지정 : "); if (pickrefs == null) return Result.Succeeded; 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); } Line pipeline = null;//메인 배관 선형 //메인 파이프 간격띄우기 구하기 if (elem1 is Pipe) { MainPipe = elem1 as Pipe; pipeline = (MainPipe.Location as LocationCurve).Curve as Line; mainSp = pipeline.GetEndPoint(0); mainEp = pipeline.GetEndPoint(1); //m_MainHgt = pipeline.GetEndPoint(0).Z; m_MainHgt = MainPipe.LevelOffset; //현재 레벨의 높이 구하기.(active Level을 구하면 3D에서 작도가 안됌.) m_GenLevElevation = Unit.FeetToMM(pipeline.GetEndPoint(0).Z - MainPipe.LevelOffset); //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; } //헤드 값 지정 foreach (ElementId elemid in m_SpklrList) { FamilyInstance family = (doc.GetElement(elemid)) as FamilyInstance; ConnectorSet conSet = family.MEPModel.ConnectorManager.Connectors; foreach (Connector con in conSet) { IntersectionResult 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)); lst_objSprinkler.Add(objSprinKler); m_SpklrHgtLst.Add(con.Origin.Z); break; } } //헤드 수직점에 따른 헤드 값 정렬 lst_objSprinkler.Sort(OC); 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); } //나눈 그룹 리스트에 담기. if (Group.Count > 0) m_TotalObjLst.Add(Group); }//while end //총 리스트에서 헤드가 1개일 때 그 헤드 리스트 앞 뒤 중 가까운쪽에 넣고 삭제 m_TotalObjLst = Spkr_Func.RemoveSingleObjLst(m_TotalObjLst); //대화상자 기본값 설정 Form_Upward dlg = new Form_Upward(); dlg.MainHeight = Math.Round(Unit.FeetToMM(m_MainHgt), 3); dlg.BranchHeight = Math.Round(Unit.FeetToMM(m_MainHgt), 3) + 300; dlg.CapDist = 100; dlg.m_HgtLst = m_SpklrHgtLst; dlg.SpkrTol = 5; dlg.TeeReducerDist = 100; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.Cancel) return Result.Succeeded; //대화상자 값 가져오기 m_MainHgt = dlg.MainHeight; m_BranchHgt = dlg.BranchHeight; m_CapDist = dlg.CapDist; m_Tolerance = dlg.SpkrTol; m_TReducerDist = dlg.TeeReducerDist; //교차배관, 가지배관 높이 재지정 m_MainHgt = m_MainHgt + m_GenLevElevation; m_BranchHgt = m_BranchHgt + m_GenLevElevation; //처음 관경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); 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); 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; } public List ProcessingSpkr(List RangeLeftLst, List RangeRightLst, Element MainElem, List HeadDiaLst) { 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.UpSPJOIN(obj1, obj2, m_BranchHgt, ref sp_In, i + 1, HeadDiaLst); //틀어진 점에서 작도할 거리가 나오지 않으면 작도 X if (mainPts == null) { if (RangeLeftLst.Count() - 1 >= i + 2) { mainPts = Spkr_Func.UpSPJOIN(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.GetMain2LastpipePoint(RangeLeftLst.Last(), m_BranchHgt); m_LeftPtLst.Add(lastPt); m_LeftPtLst.Reverse(); //캡 파이프 XYZ capPt = Spkr_Func.GetCAPpoint(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.ConnectHead2pipe(RangeLeftLst, newPipes, HeadDiaLst,m_TReducerDist); doc.Regenerate(); 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.UpSPJOIN(obj1, obj2, m_BranchHgt, ref sp_In, i + 1, HeadDiaLst); //틀어진 점에서 작도할 거리가 나오지 않으면 작도 X if (mainPts == null) { if (RangeRightLst.Count() - 1 >= i + 2) { mainPts = Spkr_Func.UpSPJOIN(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.GetMain2LastpipePoint(RangeRightLst.Last(), m_BranchHgt); m_RightPtLst.Add(lastPt); m_RightPtLst.Reverse(); //캡 파이프 XYZ capPt = Spkr_Func.GetCAPpoint(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.ConnectHead2pipe(RangeRightLst, newPipes, HeadDiaLst, m_TReducerDist); doc.Regenerate(); 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 (Math.Abs(firstDist - nextDist) > Unit.MMToFeet(m_Tol) || Math.Abs(firstDist - nextDist) < 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, Math.Abs(firstDist - nextDist)); 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); //메인관-커넥터 가까운 점 IntersectionResult interRes = MainLine.Project(spkrCon.First().Origin); XYZ interPt = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, spkrCon.First().Origin.Z); //스프링클러 헤드 정보 spkr.HeadCon = spkrCon.First(); spkr.m_Headpt = spkrCon.First().Origin; spkr.m_InterPt = interPt; spkr.m_SpID = family.Id; resLst.Add(spkr); } return resLst; } 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; } } public class SelectionFilter : 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; } } } }