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.ColorSort; using System.Resources; using KMBIM.Revit.Tools.Cmd.PipeMatchInterval; namespace KMBIM { /// /// Made By Lee Juho, DCS /// 2021.08 /// /// 1. 위치 조정할 배관 선택 /// 2. 기준 배관 선택 /// 3. 기준 배관의 LocationCurve의 벡터를 구해서 90도 눕힌 다음 가상의 선을 만들고 그 선에 위치 조정할 배관들 커넥터의 좌표를 투영 /// 4. 투영된 점들간의 간격 구하기 = 배관 중심과 중심 간의 간격 /// 5. LocationCurve의 시작점과 각 배관들의 거리에 따라 리스트 정렬, /// 6. 3에서 구한 LocationCurve의 시작점 -> 기준 배관 벡터 & 움직일 배관 -> 기준 배관이 동일한지 구분해서 배관을 두 개의 그룹으로 쪼개기 /// 7. WinForm 띄워서 단열재 두께 입력받기 /// 8. 6에서 쪼갠 리스트를 백터로 향하는 방향으로 따로 for문 루프 돌리기 /// 9. 원래 위치에 비해 배관이 더 멀어져야 하는지, 가까워져야 하는지에 따라 위치 조정 /// [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class PipeMatchInterval : IExternalCommand { UIApplication uiapp; UIDocument uidoc; static public Autodesk.Revit.DB.Document doc = null; Autodesk.Revit.ApplicationServices.Application app = null; public static List movePipeList = new List(); public static Pipe dirPipe = null; public static List mpiList = new List(); public static List RightMpiLst = new List(); public static List LeftMpiLst = new List(); public static List UpMpiLst = new List(); public static List DownMpiLst = new List(); public static MovePipeInfo dirMpi = new MovePipeInfo(); public static double dirPipeInsul = 0; public static double userPipeInsulCri = 0; 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; IList rList = uidoc.Selection.PickObjects(ObjectType.Element, new PipeSelectionFilter(), "위치 바꿀 배관 선택: "); movePipeList.Clear(); //바꿀 배관 foreach (Reference refer in rList) { if (refer == null) return Result.Cancelled; Pipe movePipe = doc.GetElement(refer.ElementId) as Pipe; movePipeList.Add(movePipe); } //기준 배관 Reference r = uidoc.Selection.PickObject(ObjectType.Element, new PipeSelectionFilter(), "기준 배관 선택: "); if (r == null) return Result.Failed; dirPipe = doc.GetElement(r.ElementId) as Pipe; List criPipeCon = Util.GetElementConnectors(dirPipe);//기준 파이프 커넥터들 //기준 배관 외경 Parameter criPipeODiaParam = dirPipe.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER); double criPipeODia = Unit.FeetToMM(criPipeODiaParam.AsDouble()); //기준 배관 단열재 두께 Parameter criPipeInsulThickParam = dirPipe.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS); dirPipeInsul = Unit.FeetToMM(criPipeInsulThickParam.AsDouble()); LocationCurve criPipeLC = dirPipe.Location as LocationCurve;//기준 배관 직선 구하기 Line criPipeLine = criPipeLC.Curve as Line; XYZ dirSp = null, dirEp = null; Util.GetStartEndPoint(dirPipe, ref dirSp, ref dirEp); XYZ midPt = Util.Midpoint(dirSp, dirEp); //거리 구하기 위해 z값 0 (Z값 있으면 배관 간격띄우기 값이 다를 때 대각선 값 나옴) XYZ midZ0Pt = Util.PointZ0(midPt); //XYZ stPt = criPipeLine.GetEndPoint(0); //XYZ endPt = criPipeLine.GetEndPoint(1); //XYZ midPt = Util.Midpoint(stPt, endPt); //간격 띄우기 값으로 가로로 나열되어 있는지, 세로(Z축 방향)로 나열되어 있는지 파악 double dirPipeOffset = dirPipe.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM).AsDouble(); double movePipeOffset = movePipeList[0].get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM).AsDouble(); //초기화 안하면 명령어 실행할 때마다 중복 오류 mpiList.Clear(); RightMpiLst.Clear(); LeftMpiLst.Clear(); UpMpiLst.Clear(); DownMpiLst.Clear(); foreach (Pipe p in movePipeList) { //if (dirPipe.Id.Equals(p.Id)) continue; XYZ moveSp = null, moveEp = null; Util.GetStartEndPoint(p, ref moveSp, ref moveEp); Line pVirLine = Line.CreateUnbound(moveSp, (moveEp - moveSp).Normalize()); IntersectionResult interRes = pVirLine.Project(midZ0Pt); XYZ closePt = interRes.XYZPoint; //거리 구하기 위해 z값 0 (Z값 있으면 배관 간격띄우기 값이 다를 때 대각선 값 나옴) XYZ closeZ0Pt = Util.PointZ0(closePt); //Util.Pyosi(doc, closeZ0Pt, 1); //MessageBox.Show("1"); MovePipeInfo mpi = new MovePipeInfo(); mpi.PipeToMove = p; mpi.InterPt = closePt; mpi.InterZ0Pt = closeZ0Pt; //움직일 배관 간격 띄우기 값 Parameter mvPipeOffsetParam = p.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM); double mvPipeOffset = Unit.FeetToMM(mvPipeOffsetParam.AsDouble()); mpi.Offset = mvPipeOffset; //움직일 배관 호칭경 Parameter mvPipeNorDiaParam = p.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); double mvPipeNorDia = Unit.FeetToMM(mvPipeNorDiaParam.AsDouble()); mpi.NormalDiameter = mvPipeNorDia; //움직일 배관 외경 Parameter mvPipeODiaParam = p.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER); double mvPipeODia = Unit.FeetToMM(mvPipeODiaParam.AsDouble()); mpi.OuterDia = mvPipeODia; mpi.OuterDiaRound = Math.Round(mpi.OuterDia, 1); //움직일 배관 단열재 두께 Parameter mvPipeInsulThickParam = p.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS); double mvPipeInsulThick = Unit.FeetToMM(mvPipeInsulThickParam.AsDouble()); mpi.InsultionThick = mvPipeInsulThick; //배관 중심과 중심 간의 간격 double distForSort = Unit.FeetToMM(mpi.InterZ0Pt.DistanceTo(midZ0Pt)); //MessageBox.Show(distForSort.ToString()); mpi.DistanceFromCri = distForSort;//나열을 위한 클래스에 집어넣기 mpiList.Add(mpi); } //거리순으로 나열, 오름차순 mpiList.Sort((a, b) => a.DistanceFromCri.CompareTo(b.DistanceFromCri)); //기준 배관 기준으로 왼쪽 오른쪽 나눔 foreach (MovePipeInfo info in mpiList) { //기준 배관 넘어감 if (dirPipe.Id.Equals(info.PipeToMove.Id)) { dirMpi = info; continue; } //기준 배관 기준 왼쪽 오른쪽 나누기 if (Util.isRightPoint(info.InterZ0Pt, dirSp, dirEp) == true) RightMpiLst.Add(info); else LeftMpiLst.Add(info); } //거리순으로 나열, 오름차순 RightMpiLst.Sort((a, b) => a.DistanceFromCri.CompareTo(b.DistanceFromCri)); LeftMpiLst.Sort((a, b) => a.DistanceFromCri.CompareTo(b.DistanceFromCri)); //기준 배관 기준으로 위 아래 나눔 foreach (MovePipeInfo info in mpiList) { //기준 배관 넘어감 if (dirPipe.Id.Equals(info.PipeToMove.Id)) { dirMpi = info; continue; } //기준 배관 기주 위 아래 나누기 if (midPt.Z < info.InterPt.Z) UpMpiLst.Add(info); else DownMpiLst.Add(info); } //간격띄우기 값 순으로 나열 //UpMpiLst.Sort((a, b) => Math.Abs(midPt.Z - a.InterPt.Z).CompareTo(midPt.Z - b.InterPt.Z)); //DownMpiLst.Sort((a, b) => Math.Abs(midPt.Z - a.InterPt.Z).CompareTo(midPt.Z - b.InterPt.Z)); UpMpiLst.Sort((a, b) => a.Offset.CompareTo(b.Offset)); DownMpiLst.Sort((a, b) => a.Offset.CompareTo(b.Offset)); DownMpiLst.Reverse(); //대화상자 시작 SetOffset so = new SetOffset(); so.ShowDialog(); //RightMpiLst.Reverse(); so.doc = doc; double m_Offset = so.offsetValue;//간격 띄우기 int idx_DirSort = so.m_RadIdx;//정렬 방향 (수평/수직) if (so.isConfirmed == false) return Result.Cancelled;//취소시 명령어 종료 //Transaction 실행 using (Transaction trans = new Transaction(doc)) { trans.Start("Start"); // 기준 배관 단열재 두께 변경 if (dirMpi.InsultionThick != dirMpi.UserInsultionThick) { //유저가 기준 배관 단열재 두께를 변경한 경우 Util.SetPipeInsulationThickness(doc, dirMpi.PipeToMove, Unit.MMToFeet(dirMpi.UserInsultionThick)); } //정렬 수평일 경우 if (idx_DirSort == 0) { //기준배관 오른쪽 배관 단열재 두께 변경 foreach (MovePipeInfo rightInfo in RightMpiLst) { if (rightInfo.InsultionThick != rightInfo.UserInsultionThick) { //유저가 단열재 두께를 변경한 경우 Util.SetPipeInsulationThickness(doc, rightInfo.PipeToMove, Unit.MMToFeet(rightInfo.UserInsultionThick)); } } //기준배관 왼쪽 배관 단열재 두께 변경 foreach (MovePipeInfo leftInfo in LeftMpiLst) { if (leftInfo.InsultionThick != leftInfo.UserInsultionThick) { //유저가 단열재 두께를 변경한 경우 Util.SetPipeInsulationThickness(doc, leftInfo.PipeToMove, Unit.MMToFeet(leftInfo.UserInsultionThick)); } } //수평 프로세스 MoveHorizontalProcess(so, RightMpiLst, LeftMpiLst, dirMpi, midZ0Pt); } else if(idx_DirSort==1)//정렬 수직일 경우 { //기준배관 위쪽 배관 단열재 두께 변경 foreach (MovePipeInfo UpInfo in UpMpiLst) { if (UpInfo.InsultionThick != UpInfo.UserInsultionThick) { //유저가 단열재 두께를 변경한 경우 Util.SetPipeInsulationThickness(doc, UpInfo.PipeToMove, Unit.MMToFeet(UpInfo.UserInsultionThick)); } } //기준배관 아래쪽 배관 단열재 두께 변경 foreach (MovePipeInfo DownInfo in DownMpiLst) { if (DownInfo.InsultionThick != DownInfo.UserInsultionThick) { //유저가 단열재 두께를 변경한 경우 Util.SetPipeInsulationThickness(doc, DownInfo.PipeToMove, Unit.MMToFeet(DownInfo.UserInsultionThick)); } } //수직 프로세스 MoveVerticalProcess(so, UpMpiLst, DownMpiLst, dirMpi, midPt); } trans.Commit(); }//end trans } catch (Exception e) { MessageBox.Show(e.Message); } return Result.Succeeded; } //Method-------------------------------------------------------------------------------------------------------------- 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 double GetMinValue(List doubleList) { double minLength = doubleList[0]; for (int i = 0; i < doubleList.Count(); i++) { //최솟값 구하기 if (minLength > doubleList[i]) { minLength = doubleList[i]; } } return minLength; } public double RTD(double radian) { return radian * (180.0 / Math.PI); } /// /// 실제 이동 거리 구해 배관 이동 /// /// 대화상자 /// 기준배관 오른쪽 배관리스트 /// 기준배관 왼쪽 배관리스트 /// 기준 배관 /// 기준배관 중간점 public void MoveHorizontalProcess(SetOffset dlg, List RightInfoLst, List LeftInfoLst, MovePipeInfo dirMpi, XYZ dirPipeMidPt) { XYZ dirInterPt = dirPipeMidPt; MovePipeInfo dirInfo = dirMpi; //기준배관 오른쪽 리스트 실제 foreach (MovePipeInfo info in RightInfoLst) { //기준배관과 교차점 중심 간 거리 double dirDist = Unit.FeetToMM(info.InterZ0Pt.DistanceTo(dirInterPt)); //사용자가 단열재 두께를 변경했을 때 double realDist = 0; if (dirInfo.InsultionThick != dirInfo.UserInsultionThick) { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.UserInsultionThick); } else//변경 안 했을 때 { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.InsultionThick); } //이전 배관과 거리 변수 추가 info.Distance = realDist; //갱신 dirInfo = info; dirInterPt = info.InterZ0Pt; } dirInterPt = dirPipeMidPt; dirInfo = dirMpi; //기준배관 왼쪽 리스트 foreach (MovePipeInfo info in LeftInfoLst) { //기준배관과 교차점 중심 간 거리 double dirDist = Unit.FeetToMM(info.InterZ0Pt.DistanceTo(dirInterPt)); //사용자가 단열재 두께를 변경했을 때 double realDist = 0; if (dirInfo.InsultionThick != dirInfo.UserInsultionThick) { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.UserInsultionThick); } else//변경 안 했을 때 { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.InsultionThick); } //이전 배관과 거리 변수 추가 info.Distance = realDist; //갱신 dirInfo = info; dirInterPt = info.InterZ0Pt; } //정렬방향 - 수평 if (dlg.m_RadIdx == 0) { //기준배관 방향으로 옮긴 배관들 중 마지막으로 옮긴 거리 double lastRedDist = 0; //기준파이프 오른쪽 파이프 리스트 foreach (MovePipeInfo rp in RightMpiLst) { double redDist = 0; XYZ vec = (dirPipeMidPt - rp.InterZ0Pt).Normalize(); if (rp.UserInsultionThick != rp.InsultionThick) { if (rp.UserInsultionThick > rp.InsultionThick) redDist = rp.Distance - dlg.offsetValue + lastRedDist - (rp.UserInsultionThick - rp.InsultionThick); else redDist = rp.Distance - dlg.offsetValue + lastRedDist + (rp.InsultionThick - rp.UserInsultionThick); } else redDist = rp.Distance - dlg.offsetValue + lastRedDist; //redDist = rp.Distance - m_Offset + lastRedDist; XYZ movePt = Util.Polar(rp.InterZ0Pt, vec, Unit.MMToFeet(redDist)); XYZ tranVec = (movePt - rp.InterZ0Pt); ElementTransformUtils.MoveElement(doc, rp.PipeToMove.Id, tranVec); lastRedDist = redDist; } lastRedDist = 0; //기준파이프 왼쪽 파이프 리스트 foreach (MovePipeInfo lp in LeftMpiLst) { double redDist = 0; XYZ vec = (dirPipeMidPt - lp.InterZ0Pt).Normalize(); if (lp.UserInsultionThick != lp.InsultionThick) { if (lp.UserInsultionThick > lp.InsultionThick) redDist = lp.Distance - dlg.offsetValue + lastRedDist - (lp.UserInsultionThick - lp.InsultionThick); else redDist = lp.Distance - dlg.offsetValue + lastRedDist + (lp.InsultionThick - lp.UserInsultionThick); } else redDist = lp.Distance - dlg.offsetValue + lastRedDist; //redDist = rp.Distance - m_Offset + lastRedDist; XYZ movePt = Util.Polar(lp.InterZ0Pt, vec, Unit.MMToFeet(redDist)); XYZ tranVec = (movePt - lp.InterZ0Pt); ElementTransformUtils.MoveElement(doc, lp.PipeToMove.Id, tranVec); lastRedDist = redDist; } } } /// /// 실제 이동 거리 구해 배관 이동 /// /// 대화상자 /// 기준배관 오른쪽 배관리스트 /// 기준배관 왼쪽 배관리스트 /// 기준 배관 /// 기준배관 중간점 public void MoveVerticalProcess(SetOffset dlg, List UpInfoLst, List DownInfoLst, MovePipeInfo dirMpi, XYZ dirPipeMidPt) { //기준 배관과 가까운 순서대로 정렬 //RightMpiLst.Sort((a, b) => Math.Abs(dirPipeMidPt.Z - a.InterPt.Z).CompareTo(Math.Abs(dirPipeMidPt.Z - b.InterPt.Z))); XYZ dirInterPt = dirPipeMidPt; MovePipeInfo dirInfo = dirMpi; //기준배관 오른쪽 리스트 실제 foreach (MovePipeInfo info in UpInfoLst) { //기준배관과 교차점 중심 간 높이 //double dirDist = Unit.FeetToMM(info.InterZ0Pt.DistanceTo(dirInterPt)); double dirDist = Unit.FeetToMM(Math.Abs(info.InterPt.Z - dirInterPt.Z)); //사용자가 단열재 두께를 변경했을 때 double realDist = 0; if (dirInfo.InsultionThick != dirInfo.UserInsultionThick) { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.UserInsultionThick); } else//변경 안 했을 때 { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.InsultionThick); } //이전 배관과 거리 변수 추가 info.Distance = realDist; //갱신 dirInfo = info; dirInterPt = info.InterPt; //string a = "distance : " + info.Distance.ToString() + // "\n" + "DistanceFromCri : " + info.DistanceFromCri.ToString() + // "\n" + "interPt : " + info.InterPt.ToString() + // "\n" + "OuterDia : " + info.OuterDia.ToString(); //MessageBox.Show(a); } //기준 배관과 가까운 순서대로 정렬 //LeftMpiLst.Sort((a, b) => Math.Abs(dirPipeMidPt.Z - a.InterPt.Z).CompareTo(Math.Abs(dirPipeMidPt.Z - b.InterPt.Z))); dirInterPt = dirPipeMidPt; dirInfo = dirMpi; //기준배관 왼쪽 리스트 foreach (MovePipeInfo info in DownInfoLst) { //기준배관과 교차점 중심 간 높이 //double dirDist = Unit.FeetToMM(info.InterPt.DistanceTo(dirInterPt)); double dirDist = Unit.FeetToMM(Math.Abs(info.InterPt.Z - dirInterPt.Z)); //사용자가 단열재 두께를 변경했을 때 double realDist = 0; if (dirInfo.InsultionThick != dirInfo.UserInsultionThick) { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.UserInsultionThick); } else//변경 안 했을 때 { realDist = dirDist - (info.OuterDia / 2.0 + dirInfo.OuterDia / 2.0 + info.InsultionThick + dirInfo.InsultionThick); } //이전 배관과 거리 변수 추가 info.Distance = realDist; //갱신 dirInfo = info; dirInterPt = info.InterPt; } //정렬방향 - 수직 if (dlg.m_RadIdx == 1) { //기준배관 방향으로 옮긴 배관들 중 마지막으로 옮긴 거리 double lastRedDist = 0; //기준파이프 위쪽 파이프 리스트 foreach (MovePipeInfo up in UpMpiLst) { double redDist = 0; //XYZ vec = (dirPipeMidPt - rp.InterPt).Normalize(); XYZ vec = (new XYZ(0, 0, dirPipeMidPt.Z) - new XYZ(0, 0, up.InterPt.Z)).Normalize(); if (up.UserInsultionThick != up.InsultionThick) { if (up.UserInsultionThick > up.InsultionThick) redDist = up.Distance - dlg.offsetValue + lastRedDist - (up.UserInsultionThick - up.InsultionThick); else redDist = up.Distance - dlg.offsetValue + lastRedDist + (up.InsultionThick - up.UserInsultionThick); } else redDist = up.Distance - dlg.offsetValue + lastRedDist; //redDist = rp.Distance - m_Offset + lastRedDist; XYZ movePt = Util.Polar(up.InterPt, vec, Unit.MMToFeet(redDist)); XYZ tranVec = (movePt - up.InterPt); ElementTransformUtils.MoveElement(doc, up.PipeToMove.Id, tranVec); lastRedDist = redDist; } lastRedDist = 0; //기준파이프 아래쪽 파이프 리스트 foreach (MovePipeInfo dp in DownMpiLst) { double redDist = 0; //XYZ vec = (dirPipeMidPt - lp.InterPt).Normalize(); XYZ vec = (new XYZ(0, 0, dirPipeMidPt.Z) - new XYZ(0, 0, dp.InterPt.Z)).Normalize(); if (dp.UserInsultionThick != dp.InsultionThick) { if (dp.UserInsultionThick > dp.InsultionThick) redDist = dp.Distance - dlg.offsetValue + lastRedDist - (dp.UserInsultionThick - dp.InsultionThick); else redDist = dp.Distance - dlg.offsetValue + lastRedDist + (dp.InsultionThick - dp.UserInsultionThick); } else redDist = dp.Distance - dlg.offsetValue + lastRedDist; //redDist = rp.Distance - m_Offset + lastRedDist; XYZ movePt = Util.Polar(dp.InterPt, vec, Unit.MMToFeet(redDist)); XYZ tranVec = (movePt - dp.InterPt); ElementTransformUtils.MoveElement(doc, dp.PipeToMove.Id, tranVec); lastRedDist = redDist; } } } /// /// 기준 배관으로 다른 배관들을 다른 리스트에 담아 분류하기 /// /// 리스트1 /// 리스트2 public void DividePipesBasedOndirPipe(List infoTrue, List infoFalse) { //for (int i = 0; i < mpiList.Count(); i++) //{ // if (mpiList[i].JudgePipe == 1)//정렬 방향 & 움직일 배관에서 기준 배관으로의 백터가 동일한 경우 // { // infoTrue.Add(mpiList[i]); // } // else if (mpiList[i].JudgePipe == 0) // { // infoFalse.Add(mpiList[i]); // } // else if (mpiList[i].JudgePipe == 2) continue;//기준 배관 패스 //} } /// /// 배관 두 개 사이의 간격 구하기(중점에서 중점간 거리가 아닌 실제 겉 표면에서 부터의 겉 표면 까지의 거리) /// /// 첫번째 배관 /// 두번째 배관 /// 배관 사이의 거리 public double GetPipesDistanceMM(Pipe pipe1, Pipe pipe2) { //pipe1 배관 외경 Parameter Pipe1ODiaParam = dirPipe.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER); double Pipe1ODia = Unit.FeetToMM(Pipe1ODiaParam.AsDouble()); //pipe1 단열재 두께 Parameter pipe1InsulThickParam = dirPipe.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS); double pipe1InsultionThick = Unit.FeetToMM(pipe1InsulThickParam.AsDouble()); LocationCurve Pipe1LC = dirPipe.Location as LocationCurve;//pipe1 직선 구하기 Line Pipe1Line = Pipe1LC.Curve as Line; XYZ stPt = Pipe1Line.GetEndPoint(0); XYZ endPt = Pipe1Line.GetEndPoint(1); XYZ midPt = Util.Midpoint(stPt, endPt); //pipe1 백터의 양쪽 횡방향 백터 구하기 XYZ Pipe1Rot1 = Util.RotateVector(Pipe1Line.Direction, Util.DTR(90)); XYZ Pipe1Rot2 = Util.RotateVector(Pipe1Line.Direction, Util.DTR(270)); XYZ guideLinePt1 = Util.Polar(midPt, Pipe1Rot1, 100); XYZ guideLinePt2 = Util.Polar(midPt, Pipe1Rot2, 100); Line guideLine = Line.CreateBound(guideLinePt1, guideLinePt2);//가상의 가이드 라인 생성 //---------------------------------------------------------------------------------------- //커넥터의 좌표를 가상의 가이드 라인에 투영 List cList = Util.GetElementConnectors(pipe2); IntersectionResult interRes = guideLine.Project(cList.First().Origin); XYZ interPt = interRes.XYZPoint; //pipe2 배관 외경 Parameter pipe2ODiaParam = pipe2.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER); double pipe2ODia = Unit.FeetToMM(pipe2ODiaParam.AsDouble()); //pipe2 단열재 두께 Parameter pipe2InsulThickParam = pipe2.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS); double pipe2InsulThick = Unit.FeetToMM(pipe2InsulThickParam.AsDouble()); //배관 중심과 중심 간의 간격 double distBetweenPipesCenter = Unit.FeetToMM(interPt.DistanceTo(guideLinePt1)); double dist = distBetweenPipesCenter - (Pipe1ODia / 2 + pipe2ODia / 2 + pipe1InsultionThick + pipe2InsulThick); return dist; } /// /// 요소에 색상 지정. 가시성/그래픽에 투영/표면 재지정 없음으로 설정하면 안 보임 /// /// 색상 넣을 요소 Id /// 바꿀 색상 public void SetColor(Document doc, Element e, System.Drawing.Color SelectedColor) { FilteredElementCollector fec = new FilteredElementCollector(doc).OfClass(typeof(FillPatternElement)); ElementId fillEId = null; foreach (FillPatternElement fpe in fec) { if (fpe.GetFillPattern().IsSolidFill)//솔리드 채움으로 되어 있는 요소에만 색상 지정 가능 { fillEId = fpe.Id; break; } else MessageBox.Show("솔리드 채움으로 바꾸십시오.", "오류"); } System.Drawing.Color col = SelectedColor; Autodesk.Revit.DB.Color adeskColor = new Autodesk.Revit.DB.Color(col.R, col.G, col.B); OverrideGraphicSettings ogs = new OverrideGraphicSettings(); ogs.SetProjectionLineColor(adeskColor); ogs.SetSurfaceForegroundPatternColor(adeskColor); ogs.SetCutForegroundPatternColor(adeskColor); if (e.Id != null) { ogs.SetSurfaceForegroundPatternId(fillEId); ogs.SetCutForegroundPatternId(fillEId); ogs.SetProjectionLinePatternId(fillEId); } doc.ActiveView.SetElementOverrides(e.Id, ogs); } } }