using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.Creation; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Plumbing; using Autodesk.Revit.DB.Structure; using Autodesk.Revit.UI; using Autodesk.Revit.UI.Selection; using KDCS.Utils; using KMBIM.Revit.Tools; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using View = Autodesk.Revit.DB.View; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class AssemblyMain : 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; LanguageType lang; 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; lang = commandData.Application.Application.Language; try { var filterFam = new FilteredElementCollector(doc) .OfClass(typeof(FamilySymbol)); string temp = ""; List info_ValSymLst = new List(); List info_AttachSymLst = new List(); List NonParamSymbolLst = new List(); foreach (FamilySymbol FamSym in filterFam) { //배관 밸브류만 추출 if ((int)BuiltInCategory.OST_PipeAccessory == FamSym.Category.Id.IntegerValue) { Info_ValveSymbol info = new Info_ValveSymbol(); info.m_FamSym = FamSym; info.m_SymFamilyName = FamSym.FamilyName; //중복된 FamilyName 존재 시 추가 X bool b_Overlap = false; foreach (Info_ValveSymbol infor in info_ValSymLst) { if (infor.m_SymFamilyName == FamSym.FamilyName) { b_Overlap = true; break; } } if (b_Overlap == false) info_ValSymLst.Add(info); } //배관 부속류만 추출 if ((int)BuiltInCategory.OST_PipeFitting == FamSym.Category.Id.IntegerValue) { //aaa += "\n" + FamSym.FamilyName; Info_AttachSymbol info = new Info_AttachSymbol(); info.m_AttFamSym = FamSym; info.m_AttSymFamilyName = FamSym.FamilyName; //중복된 FamilyName 존재 시 추가 X bool b_Overlap = false; foreach (Info_AttachSymbol infor in info_AttachSymLst) { if (infor.m_AttSymFamilyName == FamSym.FamilyName) { b_Overlap = true; break; } } if (b_Overlap == false) { //유니온만 추출 //if (Util.GetFamilyPartType(info.m_AttFamSym, PartType.Transition) == true if (Util.GetFamilyPartType(info.m_AttFamSym, PartType.Union) == true) { info_AttachSymLst.Add(info); } } } } //MessageBox.Show(aaa); using(Transaction trans = new Transaction(doc)) { trans.Start("FilterNomRad"); foreach(Info_ValveSymbol info in info_ValSymLst) { FamilySymbol symbol = info.m_FamSym; if (symbol.IsActive == false) symbol.Activate(); FamilyInstance Family = doc.Create.NewFamilyInstance(XYZ.Zero, symbol, StructuralType.NonStructural); doc.Regenerate(); Definition df = GetDefinition(Family, "NomRad"); if (df == null) NonParamSymbolLst.Add(symbol.FamilyName); Util.Delete(doc, Family); doc.Regenerate(); } trans.Commit(); } //배관 관경 세그먼트 가져와야 함으로 파이프 선택 먼저하도록 변경 //어셈블리 부착할 파이프 선택 Reference pickRef = commandData.Application.ActiveUIDocument.Selection.PickObject(ObjectType.Element, new PipeSelectionFilter(), "어셈블리 연결할 배관 선택 : "); Element elem = doc.GetElement(pickRef); Form_Assembly dlg = new Form_Assembly(); dlg.info_ValSymLst = info_ValSymLst; dlg.info_AttSymLst = info_AttachSymLst; dlg.NonNomRadLst = NonParamSymbolLst; dlg.m_uidoc = uidoc; dlg.m_doc = doc; //dlg.PipeTypeName = (elem as Pipe).PipeType.Name; dlg.mainPipe = elem as Pipe; if (dlg.ShowDialog() == DialogResult.Cancel) return Result.Cancelled; List MainAssemLst = new List(); List SubAssemLst = new List(); MainAssemLst = dlg.m_MainDataLst; SubAssemLst = dlg.m_SubDataLst; double m_M2Sdist = dlg.Main2SubDist; string tmp_nonSymLst = ""; foreach (AssemblyData data in MainAssemLst) { if (data.AssemFamSymFamName != "") { FamilySymbol famSym = Util.getNameByFamily(doc, data.AssemFamSymFamName); if (famSym == null) { if (tmp_nonSymLst.Contains(data.AssemFamSymFamName) == false) tmp_nonSymLst += ("- " + data.AssemFamSymFamName + "\n"); } } } foreach (AssemblyData data in SubAssemLst) { if (data.AssemFamSymFamName != "") { FamilySymbol famSym = Util.getNameByFamily(doc, data.AssemFamSymFamName); if (famSym == null) { if (tmp_nonSymLst.Contains(data.AssemFamSymFamName) == false) tmp_nonSymLst += ("- " + data.AssemFamSymFamName + "\n"); } } } //심볼 없으면 중지 if (tmp_nonSymLst != "") { MessageBox.Show("다음 심볼이 존재하지 않습니다.\n\n" + tmp_nonSymLst, "심볼 오류"); return Result.Failed; } View view = doc.ActiveView; if (elem is Pipe) { Pipe DirPipe = elem as Pipe; Connector spCon = null, epCon = null; Util.GetStartEndConnector(DirPipe, ref spCon, ref epCon); Line PipeLine = (DirPipe.Location as LocationCurve).Curve as Line; IntersectionResult interRes = PipeLine.Project(pickRef.GlobalPoint); XYZ PipeVec = (epCon.Origin - spCon.Origin).Normalize(); XYZ ClosePt = interRes.XYZPoint; //밸브 배치할 커넥터 Connector setCon = null, SetOtherCon = null; if (ClosePt.DistanceTo(spCon.Origin) > ClosePt.DistanceTo(epCon.Origin)) { setCon = epCon; SetOtherCon = spCon; } else { setCon = spCon; SetOtherCon = epCon; } //Util.Pyosi(doc, setCon.Origin, 1); //return Result.Succeeded; XYZ SetVec = (setCon.Origin - SetOtherCon.Origin).Normalize(); XYZ SetOtherVec = (SetOtherCon.Origin - setCon.Origin).Normalize(); //첫번째 줄 생성된 객체 리스트에 저장 List FirstLineElemLst = new List(); //메인어셈블리 작도 MainAssemblyDraw(dlg, DirPipe, SetVec, setCon, ref FirstLineElemLst); //서브어셈블리 작도 SubAssemblyDraw(dlg, FirstLineElemLst, DirPipe, SetVec, dlg.subDia); } } catch (Exception e) { //MessageBox.Show("" + e); MessageBox.Show("내부 오류가 발생하였습니다.\n관경이 없는 부속류 사용 시 작도가 되지 않습니다.\n확인하여 다시 작도하시기 바랍니다.", "오류"); } return Result.Succeeded; } //바이패스가 존재하는데 연속하는 파이프가 없을 경우 시작,끝에 추가 List ByPass_AddTeePipe(List AssemLst) { List AddAssemLst = new List(); AddAssemLst.AddRange(AssemLst); //바이패스인데 첫번째 배관 데이터 다음에 심볼이 들어갈 경우 맨 앞에 300의 배관 데이터 추가 AssemblyData FirstData = AssemLst.First(); //첫번째 리스트 값이 배관일 때 if(FirstData.IsSymbol == false) { //두번쨰 리스트 값이 심볼일 때 배관 맨 앞에 추가 AssemblyData SecondData = AssemLst[1]; if (SecondData.IsSymbol == true) { AssemblyData newPipeData = new AssemblyData(); newPipeData.AssemFamSymFamName = null; newPipeData.AssemPipeDist = "300"; newPipeData.IsSymbol = false; AddAssemLst.Insert(0, newPipeData); } } AssemblyData LastData = AssemLst.Last(); //마지막 리스트 값이 배관일 때 if (LastData.IsSymbol == false) { //끝에서 두번째 리스트 값이 심볼일 때 배관 맨 뒤 추가 AssemblyData Last2ndData = AssemLst[AssemLst.Count-2]; if (Last2ndData.IsSymbol == true) { AssemblyData newPipeData = new AssemblyData(); newPipeData.AssemFamSymFamName = null; newPipeData.AssemPipeDist = "300"; newPipeData.IsSymbol = false; AddAssemLst.Insert(AddAssemLst.Count, newPipeData); } } return AddAssemLst; } //메인 어셈블리 작도 void MainAssemblyDraw(Form_Assembly dlg, Pipe DirPipe, XYZ DirVec, Connector SetCon, ref List FirstLineElemLst) { //첫번째 줄 using (Transaction trans = new Transaction(doc)) { trans.Start("1"); doc.Regenerate(); if(dlg.m_TypeIdx==0) dlg.m_MainDataLst = ByPass_AddTeePipe(dlg.m_MainDataLst); Connector LastCon = SetCon; foreach (AssemblyData data in dlg.m_MainDataLst) { List fam = new List(); if (lang == LanguageType.English_USA || lang == LanguageType.English_GB) fam = Util.getFamily(doc, "Pipe Accessories"); else if (lang == LanguageType.Korean) fam = Util.getFamily(doc, "파이프 액세서리"); FamilySymbol valve = null; if (data.IsSymbol == true)//심볼일 경우 { //밸브 로드 valve = Util.getNameByFamily(doc, data.AssemFamSymFamName); //심볼이 활성화 안되어 있으면 활성화 시킴 if (valve.IsActive == false) valve.Activate(); FamilyInstance Fam = InsertSymbolToDirectionPipe(doc, DirPipe, LastCon, valve); doc.Regenerate(); List FamConLst = Util.GetElementConnectors(Fam); XYZ FamInsertPt = (Fam.Location as LocationPoint).Point; Connector valSpCon = null, valEpCon = null; foreach (Connector con in FamConLst) { XYZ vec = (con.Origin - FamInsertPt).Normalize(); if (vec.IsAlmostEqualTo(DirVec)) valEpCon = con; else valSpCon = con; } XYZ FamVec = (valEpCon.Origin - valSpCon.Origin).Normalize(); XYZ FamReVec = (valSpCon.Origin - valEpCon.Origin).Normalize(); //유니온 일 때 if (Util.GetFamilyPartType(valve, PartType.Union)) { valSpCon.Radius = LastCon.Radius; doc.Regenerate(); Connector UniSpCon = null, UniEpCon = null; foreach (Connector con in FamConLst) { XYZ vec = (con.Origin - FamInsertPt).Normalize(); if (vec.IsAlmostEqualTo(DirVec)) UniEpCon = con; else UniSpCon = con; } if (LastCon.Owner is FamilyInstance) { XYZ plrpt = Util.Polar(LastCon.Origin, FamVec, UniSpCon.Origin.DistanceTo(LastCon.Origin)); ElementTransformUtils.MoveElement(doc, Fam.Id, plrpt - LastCon.Origin); } else { XYZ plrpt = Util.Polar(LastCon.Origin, FamReVec, UniSpCon.Origin.DistanceTo(LastCon.Origin)); LastCon.Origin = plrpt; } doc.Regenerate(); LastCon.ConnectTo(UniSpCon); LastCon = UniEpCon; } else//밸브일 때 { Definition df = GetDefinition(Fam, "NomRad"); if (df != null) { Parameter paramRad = Fam.get_Parameter(df); paramRad.Set(DirPipe.Diameter / 2.0); } else { trans.RollBack(); MessageBox.Show("패밀리에 파라미터 'NomRad'가 없습니다."); return; } doc.Regenerate(); //커넥터 위치 옮김 if (LastCon.Owner is FamilyInstance) { XYZ plrpt = Util.Polar(LastCon.Origin, FamVec, valSpCon.Origin.DistanceTo(LastCon.Origin)); ElementTransformUtils.MoveElement(doc, Fam.Id, plrpt-LastCon.Origin); } else { XYZ plrpt = Util.Polar(LastCon.Origin, FamReVec, valSpCon.Origin.DistanceTo(LastCon.Origin)); LastCon.Origin = plrpt; } doc.Regenerate(); LastCon.ConnectTo(valSpCon); LastCon = valEpCon; //ElementTransformUtils.MoveElement(doc, valveFam.Id, plrpt - LastCon.Origin); } } else//배관일 경우 { //거리 double로 변경 double PipeDist = 0; double.TryParse(data.AssemPipeDist, out PipeDist); double dist = 0; if (LastCon.Owner is FamilyInstance) { FamilyInstance lastFam = LastCon.Owner as FamilyInstance; //밸브 삽입점-커넥터 거리 구하기 XYZ Insertpt = (lastFam.Location as LocationPoint).Point; XYZ InsertZ0pt = Util.PointZ0(Insertpt); XYZ LastConZ0pt = Util.PointZ0(LastCon.Origin); dist = InsertZ0pt.DistanceTo(LastConZ0pt); } //선택 파이프 끝에서 데이터 거리만큼 떨어진 점 구하기. if (Unit.MMToFeet(PipeDist) <= dist) { continue; } XYZ plrPt = Util.Polar(LastCon.Origin, DirVec, Math.Abs(Unit.MMToFeet(PipeDist) - dist)); double dd = Unit.FeetToMM(dist); //배관 그릴 pt 리스트 List pipePts = new List(); pipePts.Add(LastCon.Origin); pipePts.Add(plrPt); List pipeLst = Util.CreatePipe(uiapp, doc, pipePts, DirPipe.MEPSystem.GetTypeId(), DirPipe.PipeType.Id, DirPipe.ReferenceLevel.Id); Pipe newPipe = pipeLst.First(); Parameter paramDia = newPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); if (paramDia != null) paramDia.Set(DirPipe.Diameter); //새로 생긴 파이프 커넥터 리스트 List ConLst = Util.GetElementConnectors(newPipe); Connector newPipeCon = null, newPipeOtherCon = null; foreach (Connector con in ConLst) { if (con.Origin.IsAlmostEqualTo(LastCon.Origin)) newPipeCon = con; else newPipeOtherCon = con; } LastCon.ConnectTo(newPipeCon); //파이프 끝 점 (파이프 생성 후 연결 안 된 점) LastCon = newPipeOtherCon; //Util.Pyosi(doc, LastCon.Origin, 0); doc.Regenerate(); FirstLineElemLst.Add(newPipeCon.Owner); } }//foreach end trans.Commit(); } } //서브 어셈블리 작도 void SubAssemblyDraw(Form_Assembly dlg, List FirstLineElemLst, Pipe DirPipe, XYZ DirVec, double SubPipeDia) { List info_branchPtLst = new List(); //두번째 줄 if (dlg.m_TypeIdx == 0) { //서브 어셈블리 리스트박스 개수가 1개 이상일 때 if (dlg.m_SubDataLst.Count > 0) { //메인 어셈블리에 배관길이가 2개 연속으로 적용된 곳 사이에 T분기 빼는 작업 if (FirstLineElemLst.Count >= 3)//4개 이상인 경우만 작동 파이프 4개일 때 분기로 작업하기 위해. { using (Transaction trans = new Transaction(doc)) { trans.Start("1"); foreach (Element el in FirstLineElemLst) { if (el is Pipe) { Connector spConnector = null, epConnector = null; Util.GetStartEndConnector(el as Pipe, ref spConnector, ref epConnector); if (epConnector.IsConnected == true) { //파이프 커넥터 다음 커넥터가 파이프면 T연결 Connector NextCon = GetNextElementConnector(epConnector); XYZ RotVec = null; if (NextCon.Owner is Pipe) { Line pipeLine = ((NextCon.Owner as Pipe).Location as LocationCurve).Curve as Line; if (Math.Abs(DirVec.Z) > Unit.MMToFeet(1)) RotVec = Util.RotateVectorX(DirVec, Util.DTR(-90)); else RotVec = Util.RotateVector(DirVec, Util.DTR(90)); //T연결할 분기 배관 작도 XYZ plrpt = Util.Polar(NextCon.Origin, RotVec, Unit.MMToFeet(dlg.Main2SubDist)); //분기 포인트 구하기. info_SubBranchPt info_subBranchPt = new info_SubBranchPt(); info_subBranchPt.branchSpCon = NextCon; info_subBranchPt.branchEpt = plrpt; info_subBranchPt.FirstPipeEpCon = epConnector; info_subBranchPt.LastPipeSpCon = NextCon; info_branchPtLst.Add(info_subBranchPt); //Util.Pyosi(doc, NextCon.Origin, 1); //Util.Pyosi(doc, plrpt, 1); } } } }//foreach end //T분기 끝점 리스트 List BranchEndConLst = new List(); foreach (info_SubBranchPt info in info_branchPtLst) { List pipePtLst = new List(); pipePtLst.Add(info.branchSpCon.Origin); pipePtLst.Add(info.branchEpt); //분기 파이프 그리기 List branchPipeLst = Util.CreatePipe(uiapp, doc, pipePtLst, DirPipe.MEPSystem.GetTypeId(), DirPipe.PipeType.Id, DirPipe.ReferenceLevel.Id); //분기 파이프 관경 변경 Pipe branchPipe = branchPipeLst.First(); Parameter paramDia = branchPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); if (paramDia != null) paramDia.Set(Unit.MMToFeet(SubPipeDia)); doc.Regenerate(); List bPipeConLst = Util.GetElementConnectors(branchPipe); //T분기 시작 커넥터 교체. foreach (Connector con in bPipeConLst) { if (con.Origin.IsAlmostEqualTo(info.branchSpCon.Origin)) { info.branchSpCon = con; break; } } //T분기 작도 FamilyInstance teeFam = doc.Create.NewTeeFitting(info.FirstPipeEpCon, info.LastPipeSpCon, info.branchSpCon); //T분기 파이프 끝 커넥터 Connector branchEpCon = Util.GetOtherConnector(info.branchSpCon); //리스트에 T분기 파이프 끝 커넥터 저장 BranchEndConLst.Add(branchEpCon); } List fam = new List(); if (lang == LanguageType.English_USA || lang == LanguageType.English_GB) fam = Util.getFamily(doc, "Pipe Accessories"); else if (lang == LanguageType.Korean) fam = Util.getFamily(doc, "파이프 액세서리"); //SubAssemblyProcess(dlg, DirPipe, DirVec, FirstLineElemLst, BranchEndConLst); //서브 어셈블리 1개 또는 여러개 일 때 if (dlg.m_SubDataLst.Count == 1) SubAssemblyOneProcess(dlg, DirPipe, DirVec, SubPipeDia, FirstLineElemLst, BranchEndConLst); else SubAssemblyMultiProcess(dlg, DirPipe, DirVec, SubPipeDia, FirstLineElemLst, BranchEndConLst); trans.Commit(); } } } } } void SubAssemblyOneProcess(Form_Assembly dlg, Pipe DirPipe, XYZ DirVec, double PipeDia, List SubLineElemLst, List BranchEpConLst) { FamilySymbol valve = null; //서브 어셈블리 개수가 1개에 밸브류일 경우 if (dlg.m_SubDataLst.Count == 1) { List ptLst = new List(); foreach (Connector con in BranchEpConLst) { ptLst.Add(con.Origin); } //파이프 생성 및 관경 변경 List newPipeLst = Util.CreatePipe2(uiapp, doc, ptLst, DirPipe.Diameter, DirPipe.MEPSystem.GetTypeId(), DirPipe.PipeType.Id, DirPipe.ReferenceLevel.Id); Pipe newPipe = newPipeLst.First(); Parameter paramDia = newPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); if (paramDia != null) paramDia.Set(Unit.MMToFeet(PipeDia)); //파이프 커넥터 리스트 List newPipeConLst = Util.GetElementConnectors(newPipeLst.First()); foreach (Connector PipeCon in newPipeConLst) { foreach (Connector branchCon in BranchEpConLst) { if (PipeCon.Origin.IsAlmostEqualTo(branchCon.Origin)) { FamilyInstance ElbowFam = doc.Create.NewElbowFitting(PipeCon, branchCon); } } } doc.Regenerate(); AssemblyData data = dlg.m_SubDataLst.First(); //심볼일 때 중심에 설치 if (data.IsSymbol == true) { List ElbowPipeConLst = Util.GetElementConnectors(newPipe); XYZ MidPt = Util.Midpoint(ElbowPipeConLst.First().Origin, ElbowPipeConLst.Last().Origin); //파이프 중심점 자르기 List divElemIdLst = Util.DivideElement(doc, newPipe, MidPt); //밸브 로드 valve = Util.getNameByFamily(doc, data.AssemFamSymFamName); //심볼이 활성화 안되어 있으면 활성화 시킴 if (valve.IsActive == false) valve.Activate(); Pipe FirstdivPipe = doc.GetElement(divElemIdLst.First()) as Pipe; List conlst = Util.GetElementConnectors(FirstdivPipe); Connector LastCon = null; foreach (Connector con in conlst) { if (MidPt.IsAlmostEqualTo(con.Origin)) LastCon = con; } //밸브 설치 후 배관과 연결 //FamilyInstance valveFam = creDoc.NewFamilyInstance(MidPt, valve, DirVec, doc.GetElement(divElemIdLst.First()), StructuralType.NonStructural); //FamilyInstance valveFam = creDoc.NewFamilyInstance(MidPt, valve, StructuralType.NonStructural); FamilyInstance valveFam = InsertSymbolToDirectionPipe(doc, DirPipe, LastCon, valve); Definition df = GetDefinition(valveFam, "NomRad"); if (df != null) { Parameter paramRad = valveFam.get_Parameter(df); paramRad.Set(Unit.MMToFeet(PipeDia) / 2.0); }; doc.Regenerate(); //밸브 커넥터 리스트 List FamConLst = Util.GetElementConnectors(valveFam); foreach (ElementId id in divElemIdLst) { Connector PipeConnector = null; Connector ValveConnector = null; Pipe divPipe = doc.GetElement(id) as Pipe; List divPipeConLst = Util.GetElementConnectors(divPipe); List closeConLst = new List(); //현재 잘린 파이프 커넥터 중 밸브와 가까운 커넥터 구하기 foreach (Connector PipeCon in divPipeConLst) { if (PipeCon.Origin.IsAlmostEqualTo(MidPt)) { PipeConnector = PipeCon; } } Connector OtherCon = Util.GetOtherConnector(PipeConnector); double minDist = double.MaxValue; XYZ MoveVec = (OtherCon.Origin - PipeConnector.Origin).Normalize(); //현재 잘린 파이프와 가까운 밸브 커넥터 구하기 foreach (Connector FamCon in FamConLst) { double dist = OtherCon.Origin.DistanceTo(FamCon.Origin); if (dist < minDist) { minDist = dist; ValveConnector = FamCon; } } //파이프 커넥터 점 밸브와 겹치는 길이만큼 옮기기 XYZ plrPt = Util.Polar(PipeConnector.Origin, MoveVec, PipeConnector.Origin.DistanceTo(ValveConnector.Origin)); PipeConnector.Origin = plrPt; //파이프 밸브 커넥터 연결 PipeConnector.ConnectTo(ValveConnector); //break; } } //한개 작도 후 리턴하여 나감. return; } } void SubAssemblyMultiProcess(Form_Assembly dlg, Pipe DirPipe, XYZ DirVec, double PipeDia, List SubLineElemLst, List BranchEpConLst) { FamilySymbol valve = null; List SubLineConLst = new List(); //2개 이상일 떄 실행 ///////////////////////////////////////////////////////////////////////////////// //서브 어셈블리 가지관 최대 길이 double m_SubBranchMaxDist = BranchEpConLst.First().Origin.DistanceTo(BranchEpConLst.Last().Origin); //서브 어셈블리 시작 끝 커넥터 Connector SubAssemSpCon = null, SubAssemEpCon = null; AssemblyData FirstData = dlg.m_SubDataLst.First(); AssemblyData LastData = dlg.m_SubDataLst.Last(); doc.Regenerate(); Connector LastCon = BranchEpConLst.First(); foreach (AssemblyData data in dlg.m_SubDataLst) { if (data.IsSymbol == true)//심볼일 경우 { //밸브 로드 valve = Util.getNameByFamily(doc, data.AssemFamSymFamName); //심볼이 활성화 안되어 있으면 활성화 시킴 if (valve.IsActive == false) valve.Activate(); //밸브 설치 후 배관과 연결 //FamilyInstance valveFam = creDoc.NewFamilyInstance(LastCon.Origin, valve, DirVec, LastCon.Owner, StructuralType.NonStructural); //FamilyInstance valveFam = creDoc.NewFamilyInstance(LastCon.Origin, valve, StructuralType.NonStructural); FamilyInstance valveFam = InsertSymbolToDirectionPipe(doc, DirPipe, LastCon, valve); doc.Regenerate(); //Util.Pyosi(doc, LastCon.Origin, 0); List FamConLst = Util.GetElementConnectors(valveFam); XYZ FamInsertPt = (valveFam.Location as LocationPoint).Point; Connector valSpCon = null, valEpCon = null; foreach (Connector con in FamConLst) { XYZ vec = (con.Origin - FamInsertPt).Normalize(); if (vec.IsAlmostEqualTo(DirVec)) valEpCon = con; else valSpCon = con; } XYZ valVec = (valEpCon.Origin - valSpCon.Origin).Normalize(); XYZ valReVec = (valSpCon.Origin - valEpCon.Origin).Normalize(); Definition df = GetDefinition(valveFam, "NomRad"); if (df != null) { Parameter paramRad = valveFam.get_Parameter(df); paramRad.Set(Unit.MMToFeet(PipeDia / 2.0)); }; doc.Regenerate(); //커넥터 위치 옮김 //XYZ plrpt = Util.Polar(LastCon.Origin, valVec, valSpCon.Origin.DistanceTo(LastCon.Origin)); XYZ plrpt = Util.Polar(LastCon.Origin, valReVec, valSpCon.Origin.DistanceTo(LastCon.Origin)); LastCon.Origin = plrpt; doc.Regenerate(); LastCon.ConnectTo(valSpCon); LastCon = valEpCon; //ElementTransformUtils.MoveElement(doc, valveFam.Id, plrpt - LastCon.Origin); // ////선택 파이프 끝 커넥터와 밸브 연결 //LastCon.ConnectTo(valSpCon); //LastCon = valEpCon; // //doc.Regenerate(); // //SubLineElemLst.Add(valEpCon.Owner); //SubLineConLst.Add(valSpCon); //SubLineConLst.Add(valEpCon); //Util.Pyosi(doc, LastCon.Origin, 0); } else//배관일 경우 { //거리 double로 변경 double PipeDist = 0; double.TryParse(data.AssemPipeDist, out PipeDist); //선택 파이프 끝에서 데이터 거리만큼 떨어진 점 구하기. XYZ plrPt = Util.Polar(LastCon.Origin, DirVec, Unit.MMToFeet(PipeDist)); //배관 그릴 pt 리스트 List pipePts = new List(); pipePts.Add(LastCon.Origin); pipePts.Add(plrPt); List pipeLst = Util.CreatePipe(uiapp, doc, pipePts, DirPipe.MEPSystem.GetTypeId(), DirPipe.PipeType.Id, DirPipe.ReferenceLevel.Id); Pipe newPipe = pipeLst.First(); Parameter paramDia = newPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); if (paramDia != null) paramDia.Set(Unit.MMToFeet(PipeDia)); //새로 생긴 파이프 커넥터 리스트 List ConLst = Util.GetElementConnectors(newPipe); Connector newPipeCon = null, newPipeOtherCon = null; foreach (Connector con in ConLst) { if (con.Origin.IsAlmostEqualTo(LastCon.Origin)) newPipeCon = con; else newPipeOtherCon = con; } LastCon.ConnectTo(newPipeCon); //파이프 끝 점 (파이프 생성 후 연결 안 된 점) LastCon = newPipeOtherCon; //Util.Pyosi(doc, LastCon.Origin, 0); doc.Regenerate(); SubLineElemLst.Add(newPipeCon.Owner); SubLineConLst.Add(newPipeCon); SubLineConLst.Add(newPipeOtherCon); } } //서브 어셈블리 엘보피팅 doc.Create.NewElbowFitting(BranchEpConLst.First(), SubLineConLst.First()); doc.Create.NewElbowFitting(BranchEpConLst.Last(), SubLineConLst.Last()); } /// /// 객체 방향으로 심볼 돌려서 삽입 /// /// 부착할 커넥터 /// 심볼(커넥터) FamilyInstance InsertSymbolToDirectionPipe(Autodesk.Revit.DB.Document doc, Pipe DirPipe, Connector PatchCon, FamilySymbol symbol) { FamilyInstance fi = null; //Line PipeLine = (DirPipe.Location as LocationCurve).Curve as Line; Connector OtherCon = Util.GetOtherConnector(PatchCon); XYZ vec = (PatchCon.Origin - OtherCon.Origin).Normalize(); if (Math.Abs(vec.Z) > Unit.MMToFeet(1)) { fi = doc.Create.NewFamilyInstance(PatchCon.Origin, symbol, StructuralType.NonStructural); //회전 Line axisRot = Line.CreateBound(PatchCon.Origin, PatchCon.Origin + XYZ.BasisY); double ang = vec.AngleTo(XYZ.BasisY); ElementTransformUtils.RotateElement(doc, fi.Id, axisRot, ang); } else fi = doc.Create.NewFamilyInstance(PatchCon.Origin, symbol, vec, DirPipe, StructuralType.NonStructural); return fi; } /// /// 매개 변수 정의를 반환합니다. /// 주어진 요소와 매개 변수 이름. /// static Definition GetDefinition(Element elem, string parameter_name) { IList ps = elem.GetParameters(parameter_name); int n = ps.Count; Debug.Assert(1 >= n, "expected maximum one shared parameters" + "named " + parameter_name); Definition d = (0 == n) ? null : ps[0].Definition; return d; } //커넥터에 연결된 다음 객체의 커넥터 구하기. public static Connector GetNextElementConnector(Connector baseCon) { Connector resCon = null; if (baseCon.IsConnected == true) { ConnectorSet ConSet = baseCon.AllRefs; ConnectorSetIterator csi = ConSet.ForwardIterator(); while (csi.MoveNext()) { Connector connected = csi.Current as Connector; if (connected != null && connected.ConnectorType == ConnectorType.End) { if (baseCon.Origin.IsAlmostEqualTo(connected.Origin)) { if (connected.IsConnected == true) { ConnectorSet ConnectedSet = null; FamilyInstance family = null; Pipe pipe = null; FlexPipe flexpipe = null; if (connected.Owner is FamilyInstance) { family = connected.Owner as FamilyInstance; ConnectedSet = family.MEPModel.ConnectorManager.Connectors; } else if (connected.Owner is Pipe) { pipe = connected.Owner as Pipe; ConnectedSet = pipe.ConnectorManager.Connectors; } else if (connected.Owner is FlexPipe) { flexpipe = connected.Owner as FlexPipe; ConnectedSet = flexpipe.ConnectorManager.Connectors; } foreach (Connector NextCon in ConnectedSet) { if (connected.Origin.IsAlmostEqualTo(NextCon.Origin, Unit.MMToFeet(0.001))) { resCon = NextCon; } } } } }//while end } } return resCon; } public class Info_ValveSymbol { public FamilySymbol m_FamSym; public string m_SymFamilyName; } public class Info_AttachSymbol { public FamilySymbol m_AttFamSym; public string m_AttSymFamilyName; } public class info_SubBranchPt { public Connector branchSpCon;//T분기 중간 커넥터(가지관 시작 커넥터) public XYZ branchEpt;//T분기 가지관 끝 점 public Connector FirstPipeEpCon;//T분기 처음 커넥터 public Connector LastPipeSpCon;//T분기 마지막 커넥터 } 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; } } } }