using Autodesk.Revit.UI; using System; using System.Collections.Generic; using System.Linq; using System.Text; using Autodesk.Revit.DB; using Autodesk.Revit.UI.Selection; using System.Threading.Tasks; using KDCS.Utils; using System.Collections; using System.Windows.Forms; using Autodesk.Revit.DB.Plumbing; using Autodesk.Revit.DB.Mechanical; using System.Xml.Linq; using Autodesk.Revit.UI.Events; using System.IO; using KMBIM.Revit.Tools; using KMBIM.Revit.Tools.Cmd.SyncPipe; /// /// 단열재를 선택적으로 고려하며 기준 배관의 간격 띄우기 값을 기준으로 나머지 선택한 배관(들)의 높이를 통일 시킨다. /// Sync pipe's offset with criteria pipe that user selected. /// Made By 이주호(Lee Juho), DCS Company, South Korea /// 2021.07.09 ~ 2021.07.13 /// namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] /* 1. 간격띄우기 값 바꿀 배관(들) 선택 2. 기준 배관 선택 3. winForm 띄워서 기준점 선택 4. 선택 받은 기준점을 토대로 연산해서 배관 간격띄우기 값 편집 */ public class SyncPipe : IExternalCommand { UIApplication uiapp; UIDocument uidoc; Autodesk.Revit.DB.Document doc = null; Autodesk.Revit.ApplicationServices.Application app = null; public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { try { //if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded; // Verify active document if (null == commandData.Application.ActiveUIDocument.Document) { message = "현재 활성화된 뷰가 없습니다."; return Result.Failed; } uiapp = commandData.Application; uidoc = uiapp.ActiveUIDocument; app = uiapp.Application; doc = uidoc.Document; List pList = new List(); IList rList = uidoc.Selection.PickObjects(ObjectType.Element, new PipeSelectionFilter(), "위치 바꿀 배관 선택: "); foreach(Reference r in rList) { if (r == null) return Result.Cancelled; Pipe movePipe = doc.GetElement(r.ElementId) as Pipe; pList.Add(movePipe); } //위치 바꿀 배관 간격 띄우기, 외경 파라미터 구하기 List movePipeParamList = new List(); List movePipeOffsetParamList = new List(); List movePipeOuterDiaParamList = new List(); List movePipeInsultionParamList = new List(); List mpdList = new List(); foreach (Pipe p in pList) { if (p == null)//선택한 것이 파이프가 아니면 패스 { continue; } Parameter mvPipeOffsetParam = p.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM);//간격 띄우기 double mvPipeOffset = mvPipeOffsetParam.AsDouble(); Parameter mvPipeODiaParam = p.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER);//외경 double mvPipeODia = mvPipeODiaParam.AsDouble(); Parameter mvPipeInsulTickParam = p.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS);//단열재 두께 double mvPipeInsulTick = mvPipeInsulTickParam.AsDouble(); movePipeParamList.Add(mvPipeOffsetParam); movePipeOffsetParamList.Add(mvPipeOffset); movePipeOuterDiaParamList.Add(mvPipeODia); //클래스를 사용해서 한 세트로 mvPipeData mpd = new mvPipeData(); mpd.Id = p.Id; mpd.Od = mvPipeODia; mpd.InsultionTick = mvPipeInsulTick; mpd.Param = mvPipeOffsetParam; //배열로 쌓기 mpdList.Add(mpd); } //기준 배관에서 필요한 데이터 추출--------------------------------------------------------------------------------------------------------- Reference refer = uidoc.Selection.PickObject(ObjectType.Element, new PipeSelectionFilter(), "기준 배관 선택: "); Pipe criteriaPipe = doc.GetElement(refer.ElementId) as Pipe; if (criteriaPipe == null) { MessageBox.Show("기준은 배관이여야 합니다.", "오류"); return Result.Failed; } Autodesk.Revit.DB.Parameter criteriaPipeOffestParam = criteriaPipe.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM); double criteriaPipeOffset = criteriaPipeOffestParam.AsDouble(); Autodesk.Revit.DB.Parameter criteriaOuterDiaParam = criteriaPipe.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER); double criteriaOuterDia = criteriaOuterDiaParam.AsDouble(); Parameter insulationParam = criteriaPipe.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS); double criteriaInsultion = insulationParam.AsDouble(); //------------------------------------------------------------------------------------------------------------------------------------ SelectLocation sl = new SelectLocation(); sl.ShowDialog(); if(sl.ccValue == 1)//윈폼에서 Cancel 누른 경우 명령 취소 { return Result.Cancelled; } //유저가 winForm에서 선택한 원하는 위치값 구하기 double newPipeOffset = GetLocationByUserInput(sl.insulValue, sl.value, criteriaPipeOffset, criteriaOuterDia, criteriaInsultion); using (Transaction tr = new Transaction(doc)) { tr.Start("start"); double mvPipeLoc = 0; //선택한 배관(들)의 배치점 구하기.(위에서 구한 위치값으로 간격띄우기값을 조정하면 기준 선에 배관이 정렬되지 않기 때문) foreach (var a in mpdList) { //단열재 등의 고려사항을 다 연산해서 배치점 구하기 mvPipeLoc = GetMovePipeLocation(sl.insulValue, sl.value, a.InsultionTick, newPipeOffset, a.Od); a.Param.Set(mvPipeLoc); } tr.Commit(); } } catch (Exception e) { //MessageBox.Show(e.Message); } return Result.Succeeded; } //기준 Offset구하기 public double GetLocationByUserInput(int insultion, int value, double criteriaPipeOffset, double criteriaOuterDia, double insultionTick) { double newPipeOffset = 0; switch (insultion) { case (1)://단열재 고려 X switch (value) { case (1): newPipeOffset = criteriaPipeOffset + (criteriaOuterDia / 2);//상부 일치 break; case (2): newPipeOffset = criteriaPipeOffset;//중간 일치 break; case (3): newPipeOffset = criteriaPipeOffset - (criteriaOuterDia / 2);//하부 일치 break; } break; case (2)://단열재 고려 O switch (value) { case (1): newPipeOffset = criteriaPipeOffset + ((criteriaOuterDia / 2) + insultionTick); break; case (2): newPipeOffset = criteriaPipeOffset + insultionTick; break; case (3): newPipeOffset = criteriaPipeOffset - ((criteriaOuterDia / 2) + insultionTick); break; } break; } return newPipeOffset; } /// /// 값 계산해서 이동할 배관들 배치점 찾기 /// /// wimForm에서 선택한 단열재 고려 여부 /// winForm에서 선택한 기준 배치점 위치(상중하) /// 단열재 두께 /// 기준 배치점 /// 내경 /// public double GetMovePipeLocation(int insulValue, int value, double insultionTick, double newPipeOffset, double od) { double mvPipeLoc = 0; switch (insulValue) { case (1)://단열제 미고려 switch (value) { case (1): mvPipeLoc = newPipeOffset - (od / 2 );//상부 break; case (2): mvPipeLoc = newPipeOffset;//중간 break; case (3): mvPipeLoc = newPipeOffset + (od / 2);//하부 break; } break; case (2)://단열재 고려 switch (value) { case (1): mvPipeLoc = newPipeOffset - (od / 2 + insultionTick);//상부 break; case (2): mvPipeLoc = newPipeOffset;//중간 break; case (3): mvPipeLoc = newPipeOffset + (od / 2 + insultionTick);//하부 break; } break; } return mvPipeLoc; } public class PipeSelectionFilter : 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 mvPipeData { public ElementId Id { get; set; } public double Od { get; set; } public double InsultionTick { get; set; } public Parameter Param { get; set; } } }