using Autodesk.Revit.DB; using Autodesk.Revit.DB.Plumbing; using Autodesk.Revit.UI; using System.Collections.Generic; using System.Linq; using System.Diagnostics; using Autodesk.Revit.UI.Selection; using System; using System.Windows.Forms; using KDCS.Utils; using View = Autodesk.Revit.DB.View; using Autodesk.Revit.DB.Structure; using Autodesk.Revit.Creation; using KMBIM.Revit.Tools; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class FixingBolt : IExternalCommand { internal class LevelComparer : IComparer { public int Compare(Autodesk.Revit.DB.Level x, Autodesk.Revit.DB.Level y) { if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } if (Util.fuzzyEqual(x.ProjectElevation, y.ProjectElevation)) { return 0; } if (x.ProjectElevation < y.ProjectElevation) { return -1; } return 1; } } UIApplication uiapp; UIDocument uidoc; Autodesk.Revit.DB.Document doc; Autodesk.Revit.Creation.Application creApp; Autodesk.Revit.Creation.Document creDoc; public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { uiapp = commandData.Application; uidoc = uiapp.ActiveUIDocument; Autodesk.Revit.ApplicationServices.Application app = uiapp.Application; doc = uidoc.Document; creApp = uiapp.Application.Create; creDoc = doc.Create; View view = doc.ActiveView; int BoltType = 0, AttachDir = 0; bool b_InsideAttach = true; string m_SetLvlName = ""; LinkedFunction linkedFunction = new LinkedFunction(); try { if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded; Form_FixingBolt dlg = new Form_FixingBolt(); dlg.revit = commandData; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.Cancel) return Result.Cancelled; BoltType = dlg.m_RadType; AttachDir = dlg.m_RadAttach; b_InsideAttach = dlg.b_Inside; m_SetLvlName = dlg.m_LvlSet; //U볼트 패밀리 로드 FamilySymbol bolt = LoadFamilys("U_bolt.rfa", null); if (bolt == null) bolt = getNameByFamily("U_bolt"); //가이드 슈 패밀리 로드 FamilySymbol shoe = LoadFamilys("Guide_Shoe.rfa", null); if (shoe == null) shoe = getNameByFamily("Guide_Shoe"); //기준면 부착 if (AttachDir == 0) { //설치 할 면 선택 //Reference FaceRef = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Face, new PlanarFaceSelectionFilter(doc), "볼트 설치할 배관 선택 : "); Reference FaceRef = null; PlanarFace pface = null; linkedFunction.SelectFaceInLinkedFile(uiapp, out pface,out FaceRef); //패밀리 인스턴스 FamilyInstance Rack = doc.GetElement(FaceRef) as FamilyInstance; //XYZ locpt = (Rack.Location as LocationPoint).Point; ////선택한 면 Face로 변경 //GeometryObject geoObject = doc.GetElement(FaceRef).GetGeometryObjectFromReference(FaceRef); ////Face rface = geoObject as Face; //PlanarFace pface = geoObject as PlanarFace; while (true) { //설치할 파이프 선택 Reference PipeRef = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new PipeSelectionFilter(), "볼트 설치할 배관 선택 : "); Pipe pickPipe = doc.GetElement(PipeRef) as Pipe; Curve PipeCur = ((pickPipe.Location) as LocationCurve).Curve; IntersectionResult interRes = PipeCur.Project(PipeRef.GlobalPoint); XYZ insertPt = interRes.XYZPoint; XYZ PipePt = insertPt; XYZ PipeSp = null, PipeEp = null; Util.GetStartEndPoint(pickPipe, ref PipeSp, ref PipeEp); //파이프 방향 XYZ DirVec = (PipeEp - PipeSp).Normalize(); XYZ rDirVec = (PipeSp - PipeEp).Normalize(); //기준면과 파이프 방향이 맞지 않을 경우 작도 X if (Rack != null) { Transform tr = Rack.GetTransform().Inverse; if (pface.FaceNormal.IsAlmostEqualTo(tr.OfVector(DirVec)) || pface.FaceNormal.IsAlmostEqualTo(tr.OfVector(rDirVec))) { MessageBox.Show("기준면과 파이프의 방향이 다릅니다.", "오류"); break; } } else { if (pface.FaceNormal.IsAlmostEqualTo(DirVec) || pface.FaceNormal.IsAlmostEqualTo(rDirVec)) { MessageBox.Show("기준면과 파이프의 방향이 다릅니다.", "오류"); break; } } using (Transaction trans = new Transaction(doc)) { trans.Start("process"); bolt.Activate(); shoe.Activate(); //기준면 배치 프로세스 bool b_tf = PickFaceProcess(FaceRef, PipeRef,pface, BoltType, b_InsideAttach, shoe, bolt); if (b_tf == false) continue; trans.Commit(); } }//while end } else if (AttachDir == 1)//구조체 부착 { while (true) { // 설치할 파이프 선택 Reference PipeRef = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new PipeSelectionFilter(), "볼트 설치할 배관 선택 : "); Pipe pickPipe = doc.GetElement(PipeRef) as Pipe; Curve PipeCur = ((pickPipe.Location) as LocationCurve).Curve; IntersectionResult interRes = PipeCur.Project(PipeRef.GlobalPoint); XYZ insertPt = interRes.XYZPoint; XYZ PipePt = insertPt; XYZ PipeSp = null, PipeEp = null; Util.GetStartEndPoint(pickPipe, ref PipeSp, ref PipeEp); //파이프 방향 XYZ DirVec = (PipeEp - PipeSp).Normalize(); XYZ rDirVec = (PipeSp - PipeEp).Normalize(); //Z값 기준 XYZ VecZ = XYZ.BasisZ; using (Transaction trans = new Transaction(doc)) { trans.Start("process"); bolt.Activate(); shoe.Activate(); //레벨 배치 프로세스 bool b_tf = StructualProcess(PipeRef, BoltType, shoe, bolt); if (b_tf == false) continue; trans.Commit(); } }//while end } else if (AttachDir == 2)//레벨 부착 { while (true) { // 설치할 파이프 선택 Reference PipeRef = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new PipeSelectionFilter(), "볼트 설치할 배관 선택 : "); Pipe pickPipe = doc.GetElement(PipeRef) as Pipe; Curve PipeCur = ((pickPipe.Location) as LocationCurve).Curve; IntersectionResult interRes = PipeCur.Project(PipeRef.GlobalPoint); XYZ insertPt = interRes.XYZPoint; XYZ PipePt = insertPt; XYZ PipeSp = null, PipeEp = null; Util.GetStartEndPoint(pickPipe, ref PipeSp, ref PipeEp); //파이프 방향 XYZ DirVec = (PipeEp - PipeSp).Normalize(); XYZ rDirVec = (PipeSp - PipeEp).Normalize(); //Z값 기준 XYZ VecZ = XYZ.BasisZ; using (Transaction trans = new Transaction(doc)) { trans.Start("process"); bolt.Activate(); shoe.Activate(); //레벨 배치 프로세스 bool b_tf = LevelProcess(PipeRef, m_SetLvlName, BoltType, shoe, bolt); if (b_tf == false) continue; trans.Commit(); } }//while end } } catch (Exception e) { //MessageBox.Show("" + e); } return Result.Succeeded; } //배치기준 부착면 선택 public bool PickFaceProcess(Reference FaceRef, Reference PipeRef,PlanarFace pFace, int BoltType, bool b_InsideAttach, FamilySymbol shoe, FamilySymbol bolt) { bool b_TF = true; FamilyInstance family = null; IntersectionResult interRes = new IntersectionResult(); //선택한 면 Face로 변경 //GeometryObject geoObject = doc.GetElement(FaceRef).GetGeometryObjectFromReference(FaceRef); //Face rface = geoObject as Face; //PlanarFace pface = geoObject as PlanarFace; Pipe PickPipe = doc.GetElement(PipeRef) as Pipe; Curve PipeCur = (PickPipe.Location as LocationCurve).Curve; interRes = PipeCur.Project(PipeRef.GlobalPoint); XYZ insertPt = interRes.XYZPoint; XYZ PipePt = insertPt; XYZ PipeSp = null, PipeEp = null; Util.GetStartEndPoint(PickPipe, ref PipeSp, ref PipeEp); Element elem = doc.GetElement(FaceRef); if(elem is FamilyInstance)//패밀리 인스터스일 때 { //Face Curve와 파이프 Curve의 교차점 리스트 구하기 List interPtLst = getFamilyInterPoint(FaceRef, PickPipe); //경계구역 내 설치 체크박스 if (b_InsideAttach == true) { //선택한 점이 면 위에 있는지 확인 if (GetPointOnLine(interPtLst, PipeRef) == false) { MessageBox.Show("기준 면 바깥 점을 선택하였습니다.", "오류"); b_TF = false; return b_TF; } ////교차점 리스트 중간점 구하기 //insertPt = Util.Polar(interPtLst[0], interPtLst[0], interPtLst[1], interPtLst[0].DistanceTo(interPtLst[1]) / 2.0); Curve PickFaceCur = Line.CreateBound(interPtLst[0], interPtLst[1]); interRes = PickFaceCur.Project(insertPt); insertPt = interRes.XYZPoint; } else { Curve PickFaceCur = Line.CreateBound(interPtLst[0], interPtLst[1]); XYZ FaceInterPt = Util.GetPointOnLine(PickFaceCur, insertPt); interRes = PipeCur.Project(FaceInterPt); XYZ PipeOnPt = interRes.XYZPoint; insertPt = Util.Polar(FaceInterPt, PipeOnPt, PipePt, PipeOnPt.DistanceTo(PipePt)); //Util.Pyosi(doc, PipeOnPt, 0); } } //호스트 객체 or 링크객체일 때 else { //경계구역 내 설치 체크박스 if (b_InsideAttach == true) { interRes = pFace.Project(insertPt); if (interRes == null) { MessageBox.Show("기준 면 바깥 점을 선택하였습니다.", "오류"); b_TF = false; return b_TF; } insertPt = interRes.XYZPoint; } else { //경계구역 외 설치 XYZ FGlobalPt = FaceRef.GlobalPoint; //기준면 선택시 GlobalPoint와 파이프 Line의 가까운 점 interRes = PipeCur.Project(FGlobalPt); XYZ PipeDirPt = interRes.XYZPoint; interRes = pFace.Project(PipeDirPt); XYZ FaceDirPt = interRes.XYZPoint; double Pipe2FaceDst = PipeDirPt.DistanceTo(FaceDirPt); insertPt = Util.Polar(insertPt, PipeDirPt, FaceDirPt, PipeDirPt.DistanceTo(FaceDirPt)); //Util.Pyosi(doc, aa, 0); } } //패밀리 생성 if (BoltType == 0) { //파이프 단열제 두께 double insulThk = Util.GetPipeInsulationThickness(doc, PickPipe); //가이드 슈일 경우 중간점과 파이프 interRes = PipeCur.Project(insertPt); XYZ ShoeInsertPt = interRes.XYZPoint; if (ShoeInsertPt.DistanceTo(insertPt) - PickPipe.Diameter / 2.0 - insulThk / 2.0 < Unit.MMToFeet(6)) { MessageBox.Show("기준면과 파이프 사이의 거리가 좁습니다.", "오류"); b_TF = false; } family = doc.Create.NewFamilyInstance(FaceRef, ShoeInsertPt, (PipeSp - PipeEp).Normalize(), shoe); } else family = doc.Create.NewFamilyInstance(FaceRef, insertPt, (PipeSp - PipeEp).Normalize(), bolt); //패밀리 업데이트 doc.Regenerate(); //Util.Pyosi(doc, PipePt, 0); //Util.Pyosi(doc, insertPt, 0); //파이프와 볼트 삽입점의 교차점 interRes = PipeCur.Project(insertPt); XYZ PipeInterPt = interRes.XYZPoint; //볼트 옵션 변경/ SetFaceBoltOpt(FaceRef, family, BoltType, PickPipe, PipeInterPt.DistanceTo(insertPt)); //XYZ zVec = (PipeSp - PipeEp).Normalize().DotProduct() XYZ zVec = new XYZ(0, 0, 1); return b_TF; } //배치기준 구조체 public bool StructualProcess(Reference PipeRef, int BoltType, FamilySymbol shoe, FamilySymbol bolt) { bool b_TF = true; FamilyInstance family = null; IntersectionResult interRes = new IntersectionResult(); //파이프-구조체 거리 double Pipe2StructualDist = 0; Reference structRef = null; Level structLevel = null; GetClosestStructrualElevation(PipeRef, out Pipe2StructualDist, out structRef, out structLevel); Pipe PickPipe = doc.GetElement(PipeRef) as Pipe; Curve PipeCur = (PickPipe.Location as LocationCurve).Curve; interRes = PipeCur.Project(PipeRef.GlobalPoint); //선택 파이프 점으로 파이프 중심점 구하기 XYZ insertPt = interRes.XYZPoint; XYZ PipePt = insertPt; XYZ PipeSp = null, PipeEp = null; Util.GetStartEndPoint(PickPipe, ref PipeSp, ref PipeEp); //참조평면 생성 XYZ p2 = new XYZ(insertPt.X + Unit.MMToFeet(10), insertPt.Y, insertPt.Z); XYZ p1 = new XYZ(insertPt.X, insertPt.Y, insertPt.Z); XYZ p3 = new XYZ(insertPt.X, insertPt.Y + Unit.MMToFeet(10), insertPt.Z); ReferencePlane referPlane = doc.Create.NewReferencePlane2(p3, p1, p2, doc.ActiveView); //doc.Create.NewReferencePlane() //구조체가 없는 경우 참조평면으로 if(structRef == null) { if (BoltType == 0) family = doc.Create.NewFamilyInstance(referPlane.GetReference(), insertPt, (PipeEp - PipeSp).Normalize(), shoe); else family = doc.Create.NewFamilyInstance(referPlane.GetReference(), insertPt, (PipeEp - PipeSp).Normalize(), bolt); family.IsWorkPlaneFlipped = true; } else {//구조체 존재할 경우 if (BoltType == 0) family = doc.Create.NewFamilyInstance(structRef, insertPt, (PipeEp - PipeSp).Normalize(), shoe); else family = doc.Create.NewFamilyInstance(structRef, insertPt, (PipeEp - PipeSp).Normalize(), bolt); } //family.IsWorkPlaneFlipped = true; doc.Regenerate(); SetStructBoltOpt(family, BoltType, PickPipe, structLevel, Pipe2StructualDist); return b_TF; } //배치기준 레벨 public bool LevelProcess(Reference PipeRef, string setLevelName, int BoltType, FamilySymbol shoe, FamilySymbol bolt) { bool b_TF = true; FamilyInstance family = null; IntersectionResult interRes = new IntersectionResult(); Pipe PickPipe = doc.GetElement(PipeRef) as Pipe; Curve PipeCur = (PickPipe.Location as LocationCurve).Curve; interRes = PipeCur.Project(PipeRef.GlobalPoint); //선택 파이프 점으로 파이프 중심점 구하기 XYZ insertPt = interRes.XYZPoint; XYZ PipePt = insertPt; XYZ PipeSp = null, PipeEp = null; Util.GetStartEndPoint(PickPipe, ref PipeSp, ref PipeEp); //레벨 찾기 Level m_SetLevel = Util.GetLevel(doc, setLevelName); if (m_SetLevel.Elevation - PickPipe.ReferenceLevel.Elevation - PickPipe.LevelOffset < 0) { MessageBox.Show("배치기준 레벨보다 파이프가 더 높이 있습니다.", "오류"); return b_TF = false; } //참조평면 생성 XYZ p2 = new XYZ(insertPt.X + Unit.MMToFeet(10), insertPt.Y, insertPt.Z); XYZ p1 = new XYZ(insertPt.X, insertPt.Y, insertPt.Z); XYZ p3 = new XYZ(insertPt.X, insertPt.Y + Unit.MMToFeet(10), insertPt.Z); ReferencePlane referPlane = doc.Create.NewReferencePlane2(p3, p1, p2, doc.ActiveView); //doc.Create.NewReferencePlane() if (BoltType == 0) family = doc.Create.NewFamilyInstance(referPlane.GetReference(), insertPt, (PipeEp - PipeSp).Normalize(), shoe); else family = doc.Create.NewFamilyInstance(referPlane.GetReference(), insertPt, (PipeEp - PipeSp).Normalize(), bolt); family.IsWorkPlaneFlipped = true; doc.Regenerate(); SetLevelBoltOpt(family, BoltType, PickPipe, m_SetLevel); return b_TF; } public bool GetPointOnLine(List ptLst, Reference PickPipeRef) { //if (ptLst.Count != 2) return; bool b_tf = true; Pipe pipe = doc.GetElement(PickPipeRef) as Pipe; Curve PipeCur = (pipe.Location as LocationCurve).Curve; IntersectionResult interRes = new IntersectionResult(); interRes = PipeCur.Project(PickPipeRef.GlobalPoint); XYZ PickPt = interRes.XYZPoint; interRes = PipeCur.Project(ptLst[0]); XYZ CurSp = interRes.XYZPoint; interRes = PipeCur.Project(ptLst[1]); XYZ CurEp = interRes.XYZPoint; //Util.Pyosi(doc, PickPt, 0); //Util.Pyosi(doc, CurSp, 0); //Util.Pyosi(doc, CurEp, 0); double totalDist = CurSp.DistanceTo(CurEp); double ADist = PickPt.DistanceTo(CurSp); double BDist = PickPt.DistanceTo(CurEp); if ((ADist + BDist) - totalDist < Unit.MMToFeet(0.00001)) b_tf = true; else b_tf = false; return b_tf; } public List getFamilyInterPoint(Reference FaceRef, Pipe PickPipe) { Element elem = doc.GetElement(FaceRef); FamilyInstance family = elem as FamilyInstance; GeometryObject geoObj = elem.GetGeometryObjectFromReference(FaceRef); PlanarFace pface = geoObj as PlanarFace; if (family == null || pface == null) return null; Curve PipeCur = (PickPipe.Location as LocationCurve).Curve; Transform tr = family.GetTransform(); Transform InverseTr = tr.Inverse; IList curveloops = pface.GetEdgesAsCurveLoops(); //curve 교차점 리스트 List interPtLst = new List(); foreach (var curveloop in curveloops) { //if (trRack == null) break; foreach (Curve curve in curveloop) { //커브 시작 끝점 z=0으로 해서 intersection 구하기 Curve TrCur = curve.CreateTransformed(tr); Curve PipeCurZ0 = LinePointZ0(PipeCur); Curve TrCurZ0 = LinePointZ0(TrCur); //Util.Pyosi(doc, PipeCurZ0.GetEndPoint(0), 0); //Util.Pyosi(doc, TrCurZ0.GetEndPoint(0), 0); IntersectionResultArray InterResArr = new IntersectionResultArray(); PipeCurZ0.Intersect(TrCurZ0, out InterResArr); //PipeCur.Intersect(TrCur, out InterResArr); if (InterResArr == null) continue; foreach (IntersectionResult interRes in InterResArr) { IntersectionResult TrInter = TrCur.Project(interRes.XYZPoint); if (TrInter == null) continue; interPtLst.Add(TrInter.XYZPoint); //Util.Pyosi(doc, TrInter.XYZPoint, 0); } } } return interPtLst; } public Curve LinePointZ0(Curve curve) { XYZ spt = new XYZ(curve.GetEndPoint(0).X, curve.GetEndPoint(0).Y, 0); XYZ ept = new XYZ(curve.GetEndPoint(1).X, curve.GetEndPoint(1).Y, 0); Curve newCur = Line.CreateBound(spt, ept) as Curve; return newCur; } public void SetFaceBoltOpt(Reference FaceRef, FamilyInstance bolt, int BoltType, Pipe pickPipe, double dst_Face2Pipe) { GeometryObject geoObject = doc.GetElement(FaceRef).GetGeometryObjectFromReference(FaceRef); PlanarFace pface = geoObject as PlanarFace; Definition df = null; //파이프 단열제 두께 double insulThk = Util.GetPipeInsulationThickness(doc, pickPipe); //가이드 슈 옵션 설정 if (BoltType == 0) { // 가이드 슈 간격 띄우기 double m_ShoeOffset = 0; Parameter paramOffset = bolt.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); if (paramOffset != null) { //paramOffset.Set(pickPipe.LevelOffset + pickPipe.ReferenceLevel.Elevation); //m_ShoeOffset = pickPipe.LevelOffset + pickPipe.ReferenceLevel.Elevation; paramOffset.Set(dst_Face2Pipe); m_ShoeOffset = dst_Face2Pipe; } //관경 변경 df = GetDefinition(bolt, "GuideShoeCoverInRad"); if (df != null) { Parameter paramCoverRad = bolt.get_Parameter(df); if (paramCoverRad != null) paramCoverRad.Set(pickPipe.Diameter / 2.0 + insulThk); } //커넥터 관경 변경 df = GetDefinition(bolt, "ConRad"); if (df != null) { Parameter paramConRad = bolt.get_Parameter(df); if (paramConRad != null) paramConRad.Set(pickPipe.Diameter / 2.0 + insulThk); } //슈 두께 3mm 고정 double m_ShoeThk = 0; df = GetDefinition(bolt, "GuideShoeCoverThk"); if (df != null) { Parameter paramCoverThk = bolt.get_Parameter(df); if (paramCoverThk != null) { paramCoverThk.Set(Unit.MMToFeet(3)); m_ShoeThk = Unit.MMToFeet(3); } } //판 두께 df = GetDefinition(bolt, "SupportThk"); if (df != null) { Parameter paramPlateThk = bolt.get_Parameter(df); if (paramPlateThk != null) paramPlateThk.Set(Unit.MMToFeet(3)); } ////가대 간격띄우기 값 //double m_RackOffset = 0; //Parameter paramRackOffset = Rack.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); //m_RackOffset = paramRackOffset.AsDouble(); //슈 지지대 높이 df = GetDefinition(bolt, "SupportHeight"); if (df != null) { Parameter paramSupportHgt = bolt.get_Parameter(df); if (paramSupportHgt != null) paramSupportHgt.Set(m_ShoeOffset - m_ShoeThk * 2 - (pickPipe.Diameter / 2.0 + insulThk)); } //슈 지지대 높이가 음수면 실행 X //if (m_ShoeOffset - m_ShoeThk * 2 - (pickPipe.Diameter / 2.0 + insulThk) < 0) b_tf = false; } else//U-볼트 옵션 설정 { //관경 df = GetDefinition(bolt, "Diameter"); if (df != null) { Parameter paramDia = bolt.get_Parameter(df); if (paramDia != null) paramDia.Set(pickPipe.Diameter + insulThk * 2); } double boltDia = 0; double m_PipeDia = Unit.FeetToMM(pickPipe.Diameter + insulThk * 2); if (m_PipeDia >= 15 && m_PipeDia <= 50) boltDia = Unit.MMToFeet(10); else if (m_PipeDia >= 65 && m_PipeDia <= 90) boltDia = Unit.MMToFeet(12); else if (m_PipeDia > 90 && m_PipeDia <= 175) boltDia = Unit.MMToFeet(16); else if (m_PipeDia > 175 && m_PipeDia <= 250) boltDia = Unit.MMToFeet(20); else if (m_PipeDia > 250 && m_PipeDia <= 400) boltDia = Unit.MMToFeet(24); else if (m_PipeDia > 400 && m_PipeDia <= 500) boltDia = Unit.MMToFeet(30); else if (m_PipeDia > 500) boltDia = Unit.MMToFeet(32); else boltDia = Unit.MMToFeet(8); //U볼트 두께 df = GetDefinition(bolt, "Bolt_Diameter"); if(df != null) { Parameter paramBoltDia = bolt.get_Parameter(df); if (paramBoltDia != null) paramBoltDia.Set(boltDia); } //// U볼트 간격 띄우기 //double m_BoltOffset = 0; //Parameter paramOffset = bolt.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); //if (paramOffset != null) // m_BoltOffset = paramOffset.AsDouble() - pickPipe.ReferenceLevel.Elevati // // n; //support 높이 df = GetDefinition(bolt, "Support_Height"); if(df != null) { Parameter paramSupportHgt = bolt.get_Parameter(df); if (paramSupportHgt != null) { paramSupportHgt.Set(dst_Face2Pipe); } } } } public void SetLevelBoltOpt(FamilyInstance bolt, int BoltType, Pipe pickPipe, Level setLevel) { Definition df = null; //파이프 단열제 두께 double insulThk = Util.GetPipeInsulationThickness(doc, pickPipe); //가이드 슈 옵션 설정 if (BoltType == 0) { //관경 변경 df = GetDefinition(bolt, "GuideShoeCoverInRad"); if (df != null) { Parameter paramCoverRad = bolt.get_Parameter(df); if (paramCoverRad != null) paramCoverRad.Set(pickPipe.Diameter / 2.0 + insulThk); } //커넥터 관경 변경 df = GetDefinition(bolt, "ConRad"); if (df != null) { Parameter paramConRad = bolt.get_Parameter(df); if (paramConRad != null) paramConRad.Set(pickPipe.Diameter / 2.0 + insulThk); } //슈 두께 3mm 고정 double m_ShoeThk = 0; df = GetDefinition(bolt, "GuideShoeCoverThk"); if (df != null) { Parameter paramCoverThk = bolt.get_Parameter(df); if (paramCoverThk != null) { paramCoverThk.Set(Unit.MMToFeet(3)); m_ShoeThk = Unit.MMToFeet(3); } } ////가대 간격띄우기 값 //double m_RackOffset = 0; //Parameter paramRackOffset = Rack.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); //m_RackOffset = paramRackOffset.AsDouble(); //판 두께 df = GetDefinition(bolt, "SupportThk"); if (df != null) { Parameter paramPlateThk = bolt.get_Parameter(df); if (paramPlateThk != null) paramPlateThk.Set(Unit.MMToFeet(3)); } //슈 지지대 높이 df = GetDefinition(bolt, "SupportHeight"); if (df != null) { Parameter paramSupportHgt = bolt.get_Parameter(df); if (paramSupportHgt != null) { //배치 레벨 높이 - 파이프 참조레벨 높이 - 파이프 간격띄우기 - 파이프 반지름 - 단열재 반지름 - 가이드 슈 두께 X 2 double m_SupportHgt = setLevel.Elevation - pickPipe.ReferenceLevel.Elevation - pickPipe.LevelOffset - pickPipe.Diameter / 2.0 - insulThk - m_ShoeThk * 2; paramSupportHgt.Set(m_SupportHgt); } } //슈 지지대 높이가 음수면 실행 X //if (m_ShoeOffset - m_ShoeThk * 2 - (pickPipe.Diameter / 2.0 + insulThk) < 0) b_tf = false; } else//U-볼트 옵션 설정 { //관경 df = GetDefinition(bolt, "Diameter"); if (df != null) { Parameter paramDia = bolt.get_Parameter(df); if (paramDia != null) paramDia.Set(pickPipe.Diameter + insulThk * 2); } double boltDia = 0; double m_PipeDia = Unit.FeetToMM(pickPipe.Diameter + insulThk * 2); if (m_PipeDia >= 15 && m_PipeDia <= 50) boltDia = Unit.MMToFeet(10); else if (m_PipeDia >= 65 && m_PipeDia <= 90) boltDia = Unit.MMToFeet(12); else if (m_PipeDia > 90 && m_PipeDia <= 175) boltDia = Unit.MMToFeet(16); else if (m_PipeDia > 175 && m_PipeDia <= 250) boltDia = Unit.MMToFeet(20); else if (m_PipeDia > 250 && m_PipeDia <= 400) boltDia = Unit.MMToFeet(24); else if (m_PipeDia > 400 && m_PipeDia <= 500) boltDia = Unit.MMToFeet(30); else if (m_PipeDia > 500) boltDia = Unit.MMToFeet(32); else boltDia = Unit.MMToFeet(8); //U볼트 두께 df = GetDefinition(bolt, "Bolt_Diameter"); if (df != null) { Parameter paramBoltDia = bolt.get_Parameter(df); if (paramBoltDia != null) paramBoltDia.Set(boltDia); } // U볼트 간격 띄우기 Parameter paramOffset = bolt.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); if (paramOffset != null) { double m_boltOffset = -(setLevel.Elevation - pickPipe.ReferenceLevel.Elevation - pickPipe.LevelOffset); paramOffset.Set(m_boltOffset); } //support 높이 df = GetDefinition(bolt, "Support_Height"); if (df != null) { Parameter paramSupportHgt = bolt.get_Parameter(df); if (paramSupportHgt != null) { double m_SupportHgt = setLevel.Elevation - pickPipe.ReferenceLevel.Elevation - pickPipe.LevelOffset; paramSupportHgt.Set(m_SupportHgt); } } } } public void SetStructBoltOpt(FamilyInstance bolt, int BoltType, Pipe pickPipe, Level setLevel, double SupportDst) { Definition df = null; //파이프 단열제 두께 double insulThk = Util.GetPipeInsulationThickness(doc, pickPipe); //가이드 슈 옵션 설정 if (BoltType == 0) { //관경 변경 df = GetDefinition(bolt, "GuideShoeCoverInRad"); if (df != null) { Parameter paramCoverRad = bolt.get_Parameter(df); if (paramCoverRad != null) paramCoverRad.Set(pickPipe.Diameter / 2.0 + insulThk); } //커넥터 관경 변경 df = GetDefinition(bolt, "ConRad"); if (df != null) { Parameter paramConRad = bolt.get_Parameter(df); if (paramConRad != null) paramConRad.Set(pickPipe.Diameter / 2.0 + insulThk); } //슈 두께 3mm 고정 double m_ShoeThk = 0; df = GetDefinition(bolt, "GuideShoeCoverThk"); if (df != null) { Parameter paramCoverThk = bolt.get_Parameter(df); if (paramCoverThk != null) { paramCoverThk.Set(Unit.MMToFeet(3)); m_ShoeThk = Unit.MMToFeet(3); } } ////가대 간격띄우기 값 //double m_RackOffset = 0; //Parameter paramRackOffset = Rack.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); //m_RackOffset = paramRackOffset.AsDouble(); //판 두께 df = GetDefinition(bolt, "SupportThk"); if (df != null) { Parameter paramPlateThk = bolt.get_Parameter(df); if (paramPlateThk != null) paramPlateThk.Set(Unit.MMToFeet(3)); } //슈 지지대 높이 df = GetDefinition(bolt, "SupportHeight"); if (df != null) { Parameter paramSupportHgt = bolt.get_Parameter(df); if (paramSupportHgt != null && setLevel != null) { double SupportHgt = 0; if (SupportDst == 0) { //배치 레벨 높이 - 파이프 참조레벨 높이 - 파이프 간격띄우기 - 파이프 반지름 - 단열재 반지름 - 가이드 슈 두께 X 2 SupportHgt = setLevel.Elevation - pickPipe.ReferenceLevel.Elevation - pickPipe.LevelOffset - pickPipe.Diameter / 2.0 - insulThk - m_ShoeThk * 2; } else { SupportHgt = SupportDst - pickPipe.Diameter / 2.0 - insulThk - m_ShoeThk * 2; } paramSupportHgt.Set(SupportHgt); } } //슈 지지대 높이가 음수면 실행 X //if (m_ShoeOffset - m_ShoeThk * 2 - (pickPipe.Diameter / 2.0 + insulThk) < 0) b_tf = false; } else//U-볼트 옵션 설정 { //관경 df = GetDefinition(bolt, "Diameter"); if (df != null) { Parameter paramDia = bolt.get_Parameter(df); if (paramDia != null) paramDia.Set(pickPipe.Diameter + insulThk * 2); } double boltDia = 0; double m_PipeDia = Unit.FeetToMM(pickPipe.Diameter + insulThk * 2); if (m_PipeDia >= 15 && m_PipeDia <= 50) boltDia = Unit.MMToFeet(10); else if (m_PipeDia >= 65 && m_PipeDia <= 90) boltDia = Unit.MMToFeet(12); else if (m_PipeDia > 90 && m_PipeDia <= 175) boltDia = Unit.MMToFeet(16); else if (m_PipeDia > 175 && m_PipeDia <= 250) boltDia = Unit.MMToFeet(20); else if (m_PipeDia > 250 && m_PipeDia <= 400) boltDia = Unit.MMToFeet(24); else if (m_PipeDia > 400 && m_PipeDia <= 500) boltDia = Unit.MMToFeet(30); else if (m_PipeDia > 500) boltDia = Unit.MMToFeet(32); else boltDia = Unit.MMToFeet(8); //U볼트 두께 df = GetDefinition(bolt, "Bolt_Diameter"); if (df != null) { Parameter paramBoltDia = bolt.get_Parameter(df); if (paramBoltDia != null) paramBoltDia.Set(boltDia); } //support 높이 df = GetDefinition(bolt, "Support_Height"); if (df != null) { Parameter paramSupportHgt = bolt.get_Parameter(df); if (paramSupportHgt != null) { if (setLevel == null) { double Radius = pickPipe.Diameter / 2.0; paramSupportHgt.Set(Radius); } else paramSupportHgt.Set(SupportDst); } } // U볼트 간격 띄우기 Parameter paramOffset = bolt.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); if (paramOffset != null) { if (SupportDst == 0)//SupportDst가 0 이면 구조체가 없어 레벨 값으로 간격띄우기 값 조정해야 함. { if (setLevel != null) { double m_boltOffset = -(setLevel.Elevation - pickPipe.ReferenceLevel.Elevation - pickPipe.LevelOffset); paramOffset.Set(m_boltOffset); }else paramOffset.Set(-pickPipe.Diameter/2.0); } else paramOffset.Set(0); } } } //파이프에서 가까운 구조체 높이 구하기 public void GetClosestStructrualElevation(Reference pickPipeRef, out double elevation, out Reference structRefer, out Level level) { elevation = 0; structRefer = null; level = null; Level NextLevel = null; Line line = (((doc.GetElement(pickPipeRef)) as Pipe).Location as LocationCurve).Curve as Line; //레벨 가져오기 List levels = getLevel(); XYZ location = pickPipeRef.GlobalPoint; if (line == null || levels.Count == 0) return; IntersectionResult intersectionResult = line.Project(pickPipeRef.GlobalPoint); if (intersectionResult == null) return; int num = 0; for (num = 0; num < levels.Count && !(location.Z < levels[num].ProjectElevation); num++) { } if (num == 0) { level = levels[0]; } else { level = levels[num - 1]; } double locElevation = location.Z - level.ProjectElevation; double CloseElevation = double.NaN; //using(Transaction trans = new Transaction(doc)) //{ // trans.Start("1"); ReferenceIntersector referInterSector = GetReferenceIntersector(); if (referInterSector == null) return; //Z값 위쪽으로 XYZ direction = new XYZ(0.0, 0.0, 1); ReferenceWithContext referenceWithContext = referInterSector.FindNearest(location, direction); if (referenceWithContext == null) { level = NextLevel; return; } Reference refer = referenceWithContext.GetReference(); if (refer == null) return; CloseElevation = refer.GlobalPoint.Z - intersectionResult.XYZPoint.Z; elevation = CloseElevation; structRefer = refer; // trans.Commit(); //} } private ReferenceIntersector GetReferenceIntersector() { Autodesk.Revit.DB.ReferenceIntersector referenceIntersect = null; if (referenceIntersect != null) { return null; } List list = new List(); list.Add(BuiltInCategory.OST_Floors); list.Add(BuiltInCategory.OST_Roofs); list.Add(BuiltInCategory.OST_StructuralFraming); list.Add(BuiltInCategory.OST_StructuralTruss); list.Add(BuiltInCategory.OST_StructuralFoundation); list.Add(BuiltInCategory.OST_Stairs); string viewName = "View3DBolt"; View3D view3D = null; FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc); FilteredElementIterator iter = filteredElementCollector.OfClass(typeof(View3D)).GetElementIterator(); iter.Reset(); while (iter.MoveNext()) { View3D tmp_view3d = iter.Current as View3D; if (null != tmp_view3d && !tmp_view3d.IsTemplate) { if (tmp_view3d.Name == viewName) { view3D = tmp_view3d; break; } } } if (view3D == null) { IEnumerable viewFamilyTypes = from elem in new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType)) let type = elem as ViewFamilyType where type.ViewFamily == ViewFamily.ThreeDimensional select type; view3D = View3D.CreateIsometric(doc, viewFamilyTypes.First().Id); if (view3D == null) { return null; } view3D.Name = viewName; foreach (BuiltInCategory item in list) { Util.SetCategoryHidden(doc, view3D, item); } if (view3D.CanModifyViewDiscipline()) { view3D.Discipline = ViewDiscipline.Coordination; } if (view3D.CanModifyDetailLevel()) { view3D.DetailLevel = Autodesk.Revit.DB.ViewDetailLevel.Fine; } if (view3D.CanModifyDisplayStyle()) { view3D.DisplayStyle = DisplayStyle.Realistic; } view3D.CropBoxActive = false; view3D.CropBoxVisible = false; view3D.IsSectionBoxActive = false; } List list2 = new List(); foreach (BuiltInCategory item2 in list) { list2.Add(new Autodesk.Revit.DB.ElementCategoryFilter(item2)); } referenceIntersect = new Autodesk.Revit.DB.ReferenceIntersector(new LogicalOrFilter(list2), FindReferenceTarget.Face, view3D); referenceIntersect.FindReferencesInRevitLinks = true; return referenceIntersect; } private List getLevel() { List LvlList = new List(); foreach(Level item in new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).OfType()) { if (item != null) LvlList.Add(item); } //레벨 높이별로 정렬 LvlList.Sort(new LevelComparer()); return LvlList; } 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; } // 패밀리 존재 여부 검토 private FamilySymbol getNameByFamily(string name) { List fiCreationDatas = new List(); //Try to get a FamilySymbol FilteredElementCollector collector = new FilteredElementCollector(doc); ICollection collection = collector.OfClass(typeof(FamilySymbol)).ToElements(); FamilySymbol Symbol; FamilySymbol target = null; foreach (Element e in collection) { Symbol = e as FamilySymbol; if (null != Symbol.Category) { if (name == Symbol.Family.Name) { // MessageBox.Show(Symbol.Family.Name); target = Symbol; break; } } } return target; } private FamilySymbol LoadFamilys(string famroot, string famname) { string versionNumber = doc.Application.VersionNumber.ToString(); //string Tmp = System.Reflection.Assembly.GetExecutingAssembly().Location; //Tmp = Tmp.Replace("\\KMBIM2019.dll", ""); string Tmp = Util.GetKMBIMLibraryFolder("Libraries\\PipeRack"); // get the active view's level for beam creation Level level = doc.GetElement(doc.ActiveView.LevelId) as Level; // load a family symbol from file FamilySymbol gotSymbol = null; String fileName = Tmp + "\\" + versionNumber + "\\" + famroot; // 아래의 이름은 패밀리 고유의 이름이다. 패밀리 작업할때 입력하게 되어있다. String name = famname; // 패밀리를 로드한다. Family fam = null; //m_document.Document.LoadFamilySymbol(fileName, "", out gotSymbol); bool sw = false; using (Transaction trans = new Transaction(doc)) { trans.Start("LoadFamily"); sw = doc.LoadFamily(fileName, out fam); trans.Commit(); } if (sw == true) { ISet fam_ids = fam.GetFamilySymbolIds(); List fam_sym_names = new List(); if (fam_ids.Count() == 0) return null; gotSymbol = (FamilySymbol)doc.GetElement(fam_ids.ElementAt(0)); } return gotSymbol; } //페이스 필터 public class PlanarFaceSelectionFilter : ISelectionFilter { Autodesk.Revit.DB.Document m_document = null; public PlanarFaceSelectionFilter(Autodesk.Revit.DB.Document doc) { m_document = doc; } public bool AllowElement(Element element) { return true; } public bool AllowReference(Reference refer, XYZ point) { if (m_document.GetElement(refer).GetGeometryObjectFromReference(refer) is PlanarFace) { return true; } return false; } } //파이프 필터 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; } } } }