using System; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using System.Diagnostics; using System.Collections.Generic; using System.Linq; using Autodesk.Revit.Creation; using Autodesk.Revit.UI.Selection; using Autodesk.Revit.DB.Structure; using System.IO; using System.Windows.Forms; using Autodesk.Revit.DB.Plumbing; using Autodesk.Revit.ApplicationServices; using KDCS.Utils; using KMBIM; using KMBIM.Revit.Tools; namespace KMBIM { // 커넥터의 좌표를 소트 하라. [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] class HeaderSteam : IExternalCommand { UIApplication uiapp; UIDocument uidoc; ExternalCommandData m_revit; Autodesk.Revit.DB.Document doc; Autodesk.Revit.Creation.Application creApp; Autodesk.Revit.Creation.Document creDoc; Autodesk.Revit.DB.View view; LanguageType lang; public List m_ArrValue = new List(); public List m_ArrHdValue = new List(); public List m_ArrDia = new List(); double hd1; // 사용자가 선택한 메인ㅌ 헤더의 관경 Connector outvalveconn = null, trapvalveconn = null; double maxdist = 0.0; // 헤더 다리의 최대거리 double footdia = 0.0; //헤더 다리의 지름 double flangedia = 0.0; //플랜지의 지름 double flangelen = 0.0; //플랜지의 길이 int totalfooter = 0; // 전체 기둥의개수 double[] hd_loc_dst; // 가지관의 거리를 기억하는 배열 double hd2; // 해더의 총 길이 double[] gd_List = new double[10]; // 헤더 지지관의 거리? double[] flst = new double[7]; double m_headHight = 0.0; //헤더 높이 int gi_ListEA; //헤더 지지다리의 갯수 int Cntnum = -1; Autodesk.Revit.Creation.ItemFactoryBase m_CreationBase; XYZ p1 = new XYZ(); // 삽입점 XYZ p2 = new XYZ(); //방향 double[] borlst; // 관경리스트 int ListBoxCnt = -1; // 다이얼로그에서 설정한 관경의 목록의 개수 int ListBoxCnt2 = -1; // 다이얼로그에서 설정한 관경의 목록의 개수 public const double PI = 3.14159265358; public double ksv = 7.545932; //2300을 pit로 변환해놓은값 //패밀리 경로 public string str_Globepath = null, str_Safepath = null; public PipingSystemType pSysType = null; public double m_ControlValHgt = 0; public List SysTypeNameLst = new List(); public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit, ref string message, ElementSet elements) { if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded; uiapp = revit.Application; uidoc = uiapp.ActiveUIDocument; doc = uidoc.Document; m_revit = revit; creApp = uiapp.Application.Create; creDoc = doc.Create; view = doc.ActiveView; lang = revit.Application.Application.Language; try { //파이프 시스템 유형 리스트에 넣기 List m_pipeSysTypeList = new List(); ICollection SysTypeCollection = new FilteredElementCollector(doc).OfClass(typeof(PipingSystemType)).ToElements(); foreach (Element elem in SysTypeCollection) { if (elem is PipingSystemType) { PipingSystemType pipingSystemType = elem as PipingSystemType; m_pipeSysTypeList.Add(pipingSystemType.Name); } } Form_Steam dlg = new Form_Steam(); dlg.m_nMode = 4; dlg.m_HeadHgt = 800; dlg.m_ValHgt = 1300; dlg.HeaderSysTypeLst = m_pipeSysTypeList; dlg.doc = doc; if (dlg.ShowDialog() == DialogResult.OK) { //MessageBox.Show("" + dlg.m_BFpath + "\n\n" + dlg.m_Drainpath + "\n\n" + dlg.m_Safepath + "\n\n" + dlg.m_PGpath + "\n\n" + dlg.m_TGpath); //패밀리 경로 str_Globepath = dlg.m_Globepath; str_Safepath = dlg.m_Safepath; m_ControlValHgt = dlg.m_ValHgt; //pSysType = dlg.HeaderSysType; m_ArrValue = dlg.m_ArrValue; m_ArrHdValue = dlg.m_ArrHdValue; m_ArrDia = dlg.m_ArrDia; SysTypeNameLst = dlg.SelectedSysTypeNameLst; // 다이얼로그에서 설정한 데이터를 읽어 들인다. ListBoxCnt2 = dlg.listboxcnt - 1; hd1 = dlg.mainHeaderDia; //헤더의몸통의 관경 ListBoxCnt = dlg.listboxcnt; // 가지관의 갯수 m_headHight = dlg.m_HeadHgt; if (ListBoxCnt > 0) { borlst = new double[ListBoxCnt + 2]; for (int m = 0; m < ListBoxCnt; m++) { borlst[m] = dlg.dlst[m]; } } // 1. 삽입점을 묻는다. // 2. 방향을 묻는다. // 3. 헤더의를 삽입한다. // 4. 해더의 가지관을 삽입한다. //------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------ // 삽입점과 방향을 얻어온다. ObjectSnapTypes snapType = ObjectSnapTypes.Centers | ObjectSnapTypes.Endpoints | ObjectSnapTypes.Intersections | ObjectSnapTypes.Midpoints | ObjectSnapTypes.Nearest | ObjectSnapTypes.WorkPlaneGrid | ObjectSnapTypes.Points | ObjectSnapTypes.Quadrants | ObjectSnapTypes.Tangents; p1 = m_revit.Application.ActiveUIDocument.Selection.PickPoint(snapType, "삽입점"); //p2 = m_revit.Application.ActiveUIDocument.Selection.PickPoint(snapType, "방향 지정"); //선택한 점이 파이프 위의 점이면 파이프 높이 가져와야 //메인헤더와 플랜지의 값들을 계산 HDR_MDRAW(p1, 900); // 다리간의 거리및 두께를 계산 HDR_HHH(); // 헤더를 로드및 삽입 // 4 -> 입면 증기 LoadFamily(4); // 가지관을 삽입한다. //총거리 = hd2 //메인헤더의 관경은 = hd1 //지지다리간의 최대 거리 = maxdist //다리간의 거리 = gd_list //헤더 지금 = hd1 //플랜지 관경 = flangedia //플랜지 길이 = flangelen } } catch { } return Autodesk.Revit.UI.Result.Succeeded; } private void HDR_MDRAW(XYZ inp, double hg1) { int m, flg, hd_Cnt; double hp1, ds1; XYZ pnt1; flangelen = hd1 * 0.14; borlst[ListBoxCnt2 + 1] = 32.0; // 안전밸브 // 주관 길이 hd_loc_dst = new double[ListBoxCnt2 + 4]; flg = 0; hd_Cnt = 0; pnt1 = inp; hd_loc_dst[hd_Cnt] = 250; hd_Cnt++; for (m = 0; m < ListBoxCnt2 + 1; m++) { flg = flg + 1; ds1 = SL(borlst[m], borlst[flg]); //파이프간 간격 hd_loc_dst[hd_Cnt] = ds1; hd_Cnt++; // pntlst.append(pnt`1); //파이프작도 좌표 리스트 } hd_loc_dst[hd_Cnt] = 250; hd_Cnt++; // 안전밸브 // pnt1 = m_Math.Polar(pnt1, 250, ang); // pntlst.append(pnt1); FL(hd1); hp1 = flst[6] * 0.5; // 플랜지외경지름 flangedia = hp1; hd2 = 0; for (m = 0; m < hd_Cnt; m++) { hd2 = hd2 + hd_loc_dst[m]; } } //defun end HDR-MDRAW ///헤더 다리 부분 private void HDR_HHH() { double chg1, chg2, dst0, dst1, dst2; chg1 = chg2 = dst0 = dst1 = dst2 = 0.0; bool chk = false; int flg = 0; // chg1 = 지지관 지름 chg2 = 최대 지지 간격 if (hd1 == 200) { //chg1 = 65; chg1 = 100; chg2 = 1250; } else if (hd1 == 250) { //chg1 = 80; chg1 = 120; chg2 = 1500; } else if (hd1 >= 300) { //chg1 = 100; chg1 = 150; chg2 = 1750; } // cond-end footdia = chg1; //다리 기둥의 지름 chk = true; flg = 0; while (chk) { switch (flg) { case 0: gi_ListEA = HDR_2D(hd2, chg2); flg = 1 + flg; break; case 1: gi_ListEA = HDR_3D(hd2, chg2); flg = 1 + flg; break; case 2: gi_ListEA = HDR_4D(hd2, chg2); flg = 1 + flg; break; case 3: gi_ListEA = HDR_5D(hd2, chg2); flg = 1 + flg; break; default: break; } // cond-end if (gi_ListEA != 0) chk = false; } // while-end //다리의 총 개수 totalfooter = flg; // *************************** // ekfl } // defun hdr-2d private void LoadFamily(int ai_type) { string versionNumber = doc.Application.VersionNumber.ToString(); List tttt = new List(); // load a family symbol from file FamilySymbol gotSymbol = null; List fam1 = new List(); if (lang == LanguageType.English_USA || lang == LanguageType.English_GB) fam1 = getFamily("Mechanical Equipment"); else if (lang == LanguageType.Korean) fam1 = getFamily("기계 장비"); FamilySymbol valve = null; bool sw = false; //패밀리의 갯수가 하나이상이면 사용자가 선택 할수 있도록 해줘야한다. //string Tmp = System.Reflection.Assembly.GetExecutingAssembly().Location; //Tmp = Tmp.Replace("\\KMBIM2019.dll", ""); string Tmp = Util.GetKMBIMLibraryFolder("Libraries\\Header"); // get the active view's level for beam creation ViewPlan view = doc.ActiveView as ViewPlan; Level level = view.GenLevel; //Level level = uidoc.Document.GetElement(uidoc.ActiveView.LevelId) as Level; String fileName = Tmp + "\\family\\" + versionNumber + "\\new Steam Header.rfa"; // 아래의 이름은 패밀리 고유의 이름이다. 패밀리 작업할때 입력하게 되어있다. String name = "Hot Water Header (Supply)"; using (Transaction trans = new Transaction(doc)) { trans.Start("FamilyLoad"); sw = uidoc.Document.LoadFamilySymbol(fileName, name, out gotSymbol); trans.Commit(); } Definition df = null; // 패밀리를 로드한다. if (sw) { // 로드가 성공 하였다면 패밀리를 삽입한다. Level level2 = uidoc.Document.ActiveView.GenLevel; //FamilyInstance familyInstance = uidoc.Document.Create.NewFamilyInstance(new XYZ(p1.X, p1.Y, (p1.Z + Unit.CovertToAPI(800, DisplayUnitType.DUT_MILLIMETERS))), gotSymbol, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); FamilyInstance familyInstance = null; Parameter familyParam = null; using (Transaction trans = new Transaction(doc)) { trans.Start("symbolActive"); if (gotSymbol.IsActive == false) gotSymbol.Activate(); //familyInstance = uidoc.Document.Create.NewFamilyInstance(new XYZ(p1.X, p1.Y, (p1.Z + Unit.CovertToAPI(800, DisplayUnitType.DUT_MILLIMETERS))), gotSymbol, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); p1 = new XYZ(p1.X, p1.Y, 0); familyInstance = uidoc.Document.Create.NewFamilyInstance(p1, gotSymbol, StructuralType.NonStructural); uidoc.Document.Regenerate(); //헤더 높이 지정 df = GetDefinition(familyInstance, "foot1dist"); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter("Fdia"); sw = familyParam.Set(Unit.MMToFeet(m_headHight)); //sw = familyParam.Set(Unit.CovertToAPI(m_headHight, DisplayUnitType.DUT_MILLIMETERS)); uidoc.Document.Regenerate(); Parameter param = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM); double dd = Unit.FeetToMM(param.AsDouble()); param.Set(0); uidoc.Document.Regenerate(); // Family asdf = familyInstance.Symbol.Family as Family; // 플랜지의 길이 얻고 입력 // API 내부에서는 사용자가 입력하는 밀리의 단위가 아닌 피트가 쓰인다 그래서 변환해서 입력해 주어야 한다. df = GetDefinition(familyInstance, "FSize"); familyParam = familyInstance.get_Parameter(df); //Parameter familyParam = familyInstance.get_Parameter("FSize"); sw = familyParam.Set(Unit.MMToFeet(flangelen)); //sw = familyParam.Set(Unit.CovertToAPI(flangelen, DisplayUnitType.DUT_MILLIMETERS)); //플랜지의 반경 얻고 입력 df = GetDefinition(familyInstance, "Fdia"); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter("Fdia"); sw = familyParam.Set(Unit.MMToFeet(flangedia)); //sw = familyParam.Set(Unit.CovertToAPI(flangedia, DisplayUnitType.DUT_MILLIMETERS)); //다리의 지름 // API 내부에서는 사용자가 입력하는 밀리의 단위가 아닌 피트가 쓰인다 그래서 변환해서 입력해 주어야 한다. df = GetDefinition(familyInstance, "footerdia"); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter("footerdia"); sw = familyParam.Set(Unit.MMToFeet(footdia)); //sw = familyParam.Set(Unit.CovertToAPI(footdia, DisplayUnitType.DUT_MILLIMETERS)); //헤더의 반경 // API 내부에서는 사용자가 입력하는 밀리의 단위가 아닌 피트가 쓰인다 그래서 변환해서 입력해 주어야 한다. df = GetDefinition(familyInstance, "HeaderDia"); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter("HeaderDia"); sw = familyParam.Set(Unit.MMToFeet(hd1)); //sw = familyParam.Set(Unit.CovertToAPI(hd1, DisplayUnitType.DUT_MILLIMETERS)); // 헤더의 총거리 // API 내부에서는 사용자가 입력하는 밀리의 단위가 아닌 피트가 쓰인다 그래서 변환해서 입력해 주어야 한다. df = GetDefinition(familyInstance, "Totaldistance"); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter("Totaldistance"); sw = familyParam.Set(Unit.MMToFeet(hd2)); //sw = familyParam.Set(Unit.CovertToAPI(hd2, DisplayUnitType.DUT_MILLIMETERS)); for (int i = 0; i <= totalfooter; i++) { string Tm2p = string.Format("footer_{0}", i + 1); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter(Tm2p); sw = familyParam.Set(Unit.MMToFeet(gd_List[i])); //sw = familyParam.Set(Unit.CovertToAPI(gd_List[i], DisplayUnitType.DUT_MILLIMETERS)); } //안보이는 다리들을 한곳으로 모으자 if (totalfooter >= 1) { for (int i = 3; i <= 5; i++) { string Tm2p = string.Format("footer_{0}", i); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter(Tm2p); if (i - 1 > totalfooter) { familyParam.Set(Unit.MMToFeet(0)); //familyParam.Set(Unit.CovertToAPI(0, DisplayUnitType.DUT_MILLIMETERS)); } } } //보이는 다리의 거리를 준다. for (int i = 0; i <= totalfooter; i++) { string Tm2p = string.Format("footer_{0}", i + 1); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); //familyParam = familyInstance.get_Parameter(Tm2p); sw = familyParam.Set(Unit.MMToFeet(gd_List[i])); //sw = familyParam.Set(Unit.CovertToAPI(gd_List[i], DisplayUnitType.DUT_MILLIMETERS)); } // 헤더 지지 다리를 상황에 따라서 보여주고 안보여주고 하는 기능 if (totalfooter >= 1) { for (int i = 3; i <= 5; i++) { string Tm2p = string.Format("FootVisible_{0}", i); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); if (i - 1 <= totalfooter) sw = familyParam.Set(1); else sw = familyParam.Set(0); } } // 가지관들의 거리르 삽입해준다. // 상황에 따라서 압력계나 온도계는 빠질수도 있다. 압력계는 가장 처음 온도계는 두번째 안전밸브는 마지막이다. for (int i = 0; i <= hd_loc_dst.Length - 1; i++) { string Tm2p = string.Format("part_{0}", i + 1); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); sw = familyParam.Set(Unit.MMToFeet(hd_loc_dst[i])); //sw = familyParam.Set(Unit.CovertToAPI(hd_loc_dst[i], DisplayUnitType.DUT_MILLIMETERS)); } //헤더의 커넥터를 전부 모아라. FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document); collector.OfClass(typeof(PipeType)); PipeType pipeType = collector.FirstElement() as PipeType; //PipeType pipeType = null; //패밀리 위치변경 조정 doc.Regenerate(); Family family = familyInstance.Symbol.Family; ConnectorSetIterator csi = null; if (null != familyInstance.MEPModel) { int cnt = 0; // 커넥터를 거리별로 정렬 한다. DinoComparer cc = new DinoComparer(); List OtherZConLst = new List(); List bodyConLst = Util.GetElementConnectors(familyInstance); bodyConLst.Sort(cc); double LastZ = (bodyConLst.Last().Origin.Z); foreach (Connector con in bodyConLst) { tttt.Add(con); if (Math.Abs(LastZ - con.Origin.Z) > Unit.MMToFeet(1)) { OtherZConLst.Add(con); //Util.Pyosi(doc, con.Origin, 0); } } //tttt.Sort(cc); OtherZConLst.Sort(cc); foreach (Connector con in OtherZConLst) { tttt.Remove(con); } doc.Regenerate(); //outvalveconn = tttt[8]; trapvalveconn = OtherZConLst[0]; outvalveconn = OtherZConLst[1]; //tttt.RemoveAt(8); // 일단 밸브 패밀리가 로드 되어져 있는지를 보라 List fam = new List(); if (lang == LanguageType.English_USA || lang == LanguageType.English_GB) fam = getFamily("Pipe Accessories"); else if (lang == LanguageType.Korean) fam = getFamily("파이프 액세서리"); //패밀리의 갯수가 하나이상이면 사용자가 선택 할수 있도록 해줘야한다. if (fam.Count >= 1) { if (ai_type == 4) { //valve = LoadFamilys("\\data\\PV_Butterfly Valve - 20-500mm-Handle.rfa", "PV_Butterfly Valve - 20-500mm-Handle"); valve = LoadFamilys(str_Globepath); } if (valve == null) { if (ai_type == 4) { //valve = getNameByFamily("PV_Butterfly Valve - 20-500mm-Handle"); valve = getNameByFamily(Path.GetFileNameWithoutExtension(str_Globepath)); } } } if (fam.Count == 0)// 밸브 패밀리가 없다면 로드하라 { if (ai_type == 4) { //valve = LoadFamilys("\\data\\PV_Butterfly Valve - 20-500mm-Handle.rfa", "PV_Butterfly Valve - 20-500mm-Handle"); valve = LoadFamilys(str_Globepath); } if (valve == null) { if (ai_type == 4) { //valve = getNameByFamily("PV_Butterfly Valve - 20-500mm-Handle"); valve = getNameByFamily(Path.GetFileNameWithoutExtension(str_Globepath)); } } } List pipelist = new List(); List intps = new List(); // 상황에 따른 대처를 위해서 변수 생셩 if (ai_type == 4) Cntnum = 0; double m_elevation = view.GenLevel.Elevation; // 커넥터수만큼 roof를 돌면서 파이프를 그린다. for (int i = Cntnum; i < tttt.Count; i++) { if (cnt < borlst.Length - 2) { double con2valDst = Unit.MMToFeet(m_ControlValHgt) - (tttt[i].Origin.Z - m_elevation); XYZ inpt = new XYZ(tttt[i].Origin.X, tttt[i].Origin.Y, (tttt[i].Origin.Z + con2valDst*2.0)); //XYZ inpt = new XYZ(tttt[i].Origin.X, tttt[i].Origin.Y, (tttt[i].Origin.Z + Unit.CovertToAPI(1000, DisplayUnitType.DUT_MILLIMETERS))); Pipe pipe = null; pSysType = SysTypeNameLst[cnt]; pipe = Pipe.Create(doc, pSysType.Id, pipeType.Id, level.Id, tttt[i].Origin, inpt); //파이프와 헤더 몸통 커넥터 연결 List pipeConLst = Util.GetElementConnectors(pipe); foreach (Connector con in pipeConLst) { if (con.Origin.IsAlmostEqualTo(tttt[i].Origin, Unit.MMToFeet(0.01))) con.ConnectTo(tttt[i]); } if (ai_type == 4) ChangePipeSize(pipe, borlst[cnt + Cntnum]); // 냉온수일때 pipelist.Add(pipe); intps.Add(inpt); } else break; cnt++; } cnt = 0; for (int i = 0; i < pipelist.Count; i++) { // 밸브를 삽입히가. FamilyInstance fi = null; //using(Transaction trans = new Transaction(doc)) //{ // trans.Start("valve"); if (valve.IsActive == false) valve.Activate(); var vel = valve.IsActive; fi = uidoc.Document.Create.NewFamilyInstance(XYZ.Zero, valve, StructuralType.NonStructural); uidoc.Document.Regenerate(); // trans.Commit(); //} XYZ base1 = XYZ.Zero; XYZ base2 = -XYZ.BasisY; // 회전축을 정의하고 Line nline = Line.CreateUnbound(base1, base2); // 돌린다. fi.Location.Rotate(nline, Math.PI / 2); base1 = XYZ.Zero; base2 = -XYZ.BasisZ; // 다시 회전축을 정의하고 nline = Line.CreateUnbound(base1, base2); //돌린다. fi.Location.Rotate(nline, -Math.PI / 2); XYZ vec = (intps[i] - tttt[i + Cntnum].Origin).Normalize(); XYZ PipeMidPt = Util.Polar(tttt[i + Cntnum].Origin, vec, intps[i].DistanceTo(tttt[i + Cntnum].Origin) / 2.0); ElementTransformUtils.MoveElement(uidoc.Document, fi.Id, PipeMidPt); //자르기 전 파이프 시작 끝 커넥터 구하기 Connector spCon = null, epCon = null; Util.GetStartEndConnector(pipelist[i], ref spCon, ref epCon); //파이프 중간점 기준으로 자르기 List m_DivLst = Util.DivideElement(doc, pipelist[i], PipeMidPt); Connector divspCon1 = null, divepCon1 = null, divspCon2 = null, divepCon2 = null; Util.GetStartEndConnector(doc.GetElement(m_DivLst.First()) as Pipe, ref divspCon1, ref divepCon1); Util.GetStartEndConnector(doc.GetElement(m_DivLst[1]) as Pipe, ref divspCon2, ref divepCon2); //밸브 커넥터 구하기 List ValConLst = Util.GetElementConnectors(fi); //밸브 관경 파이프 관경으로 변경 ValConLst.First().Radius = pipelist[i].Diameter / 2.0; doc.Regenerate(); //밸브커넥터와 가까운 파이프커넥터끼리 연결 foreach (Connector valCon in ValConLst) { //자르기 전 파이프 시작 끝점 거리 비교 double dist1 = valCon.Origin.DistanceTo(divspCon1.Origin); double dist2 = valCon.Origin.DistanceTo(divepCon2.Origin); if (dist1 < dist2) { divepCon1.Origin = valCon.Origin; divepCon1.ConnectTo(valCon); } else { divspCon2.Origin = valCon.Origin; divspCon2.ConnectTo(valCon); } } cnt++; } } //가지관들의 관경을 삽입해준다. int intype = -1; if (ai_type == 2) intype = 2; else intype = 1; if (ai_type == 4) { for (int i = 0; i < borlst.Length - 1; i++) { string Tm2p = string.Format("part{0}_dia", i + intype); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); sw = familyParam.Set(Unit.MMToFeet(borlst[i])); //sw = familyParam.Set(Unit.CovertToAPI(borlst[i], DisplayUnitType.DUT_MILLIMETERS)); } } // 가지관이 많은데 사용자에게 보이는 문제점이 있어서 거리가 없는경우는 전부 한곳으로 겹치도록 처리 for (int i = hd_loc_dst.Length - 1; i <= 40; i++) { string Tm2p = string.Format("part_{0}", i); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); sw = familyParam.Set(Unit.MMToFeet(0)); //sw = familyParam.Set(Unit.CovertToAPI(0, DisplayUnitType.DUT_MILLIMETERS)); } // 가지관이 총 40개가 있는데 상황에 따라서 보여주고 안보여 주고 하는 기능 for (int i = 1; i <= 40; i++) { string Tm2p = string.Format("PartVisible_{0}", i); df = GetDefinition(familyInstance, Tm2p); familyParam = familyInstance.get_Parameter(df); if (i < hd_loc_dst.Length - 1) //2를 빼는 이유는 마지막 치수는 마지막 파이프 부터 끝쩜까지의 길이이기 때문에 뺀것이다. 그리고 또 하나는 꼬메소스에서 볼때 하나가 남기 때문에사용하지 않는 공간이기때문데 뺏다. sw = familyParam.Set(1); else sw = familyParam.Set(0); } //트랩 커넥터 헤더증기에서만 보여줌 df = GetDefinition(familyInstance, "PartVisible_trap"); familyParam = familyInstance.get_Parameter(df); familyParam.Set(1); // 안전밸브 파이프 그리기 XYZ safeinpt = new XYZ(tttt[borlst.Length - 2 + Cntnum].Origin.X, tttt[borlst.Length - 2 + Cntnum].Origin.Y, (tttt[borlst.Length - 2 + Cntnum].Origin.Z + Unit.MMToFeet(150))); //XYZ safeinpt = new XYZ(tttt[borlst.Length - 2 + Cntnum].Origin.X, tttt[borlst.Length - 2 + Cntnum].Origin.Y, (tttt[borlst.Length - 2 + Cntnum].Origin.Z + Unit.CovertToAPI(150, DisplayUnitType.DUT_MILLIMETERS))); //Pipe pipes = uidoc.Document.Create.NewPipe(safeinpt, tttt[borlst.Length - 2 + Cntnum], pipeType); Pipe pipes = Pipe.Create(doc, pSysType.Id, pipeType.Id, level.Id, tttt[borlst.Length - 2 + Cntnum].Origin, safeinpt); //파이프와 헤더 몸통 커넥터 연결 List pipesConLst = Util.GetElementConnectors(pipes); foreach (Connector con in pipesConLst) { if (con.Origin.IsAlmostEqualTo(tttt[borlst.Length - 2 + Cntnum].Origin, Unit.MMToFeet(0.01))) con.ConnectTo(tttt[borlst.Length - 2 + Cntnum]); } ChangePipeSize(pipes, 32); //상황에 따라서 안전밸브의 삽입여부가 결정된다. //if (ai_type == 2 || ai_type == 3 || ai_type == 4) //{ // // // 일단 밸브 패밀리가 로드 되어져 있는지를 보라 // List fam = new List(); // if (lang == LanguageType.English_USA || lang == LanguageType.English_GB) // fam = getFamily("Mechanical Equipment"); // else if (lang == LanguageType.Korean) // fam = getFamily("기계 장비"); // // FamilySymbol valves = null; // // //패밀리의 갯수가 하나이상이면 사용자가 선택 할수 있도록 해줘야한다. // if (fam.Count >= 1) // { // valve = LoadFamilys(str_Safepath); // if (valve == null) // { // valve = getNameByFamily(Path.GetFileNameWithoutExtension(str_Safepath)); // } // // // } // // if (fam.Count == 0)// 밸브 패밀리가 없다면 로드하라 // { // valve = LoadFamilys(str_Safepath); // } // // if (valve.IsActive == false) // valve.Activate(); // FamilyInstance fi = uidoc.Document.Create.NewFamilyInstance(XYZ.Zero, valve, StructuralType.NonStructural); // // XYZ base1 = XYZ.Zero; // XYZ base2 = -XYZ.BasisY; // // //uidoc.Document.Move(fi, new XYZ(safeinpt.X, safeinpt.Y, (safeinpt.Z + Unit.CovertToAPI(100, DisplayUnitType.DUT_MILLIMETERS)))); // ElementTransformUtils.MoveElement(uidoc.Document, fi.Id, new XYZ(safeinpt.X, safeinpt.Y, (safeinpt.Z + Unit.CovertToAPI(100, DisplayUnitType.DUT_MILLIMETERS)))); // // ConnectorSet connectors = pipes.ConnectorManager.Connectors; // Connector pipe_end = null; // // // 파이파의 커넥터중에 파이프의 끝나는검과 가장 가까운 커넥터를 얻어와라. // double dist = double.MaxValue; // // foreach (Connector c in connectors) // { // XYZ p = c.Origin; // XYZ valvept = new XYZ(tttt[borlst.Length - 2 + Cntnum].Origin.X, tttt[borlst.Length - 2 + Cntnum].Origin.Y, (tttt[borlst.Length - 2 + Cntnum].Origin.Z + Unit.CovertToAPI(150, DisplayUnitType.DUT_MILLIMETERS))); // double d = p.DistanceTo(safeinpt); // // if (d < dist) // { // dist = d; // pipe_end = c; // } // // break; // } // // // // Connector first = null; // Connector second = null; // // // //밸브의 커넥터를 가져와라. // ConnectorSet conns = fi.MEPModel.ConnectorManager.Connectors; // // // 밸브의 커넥터중에 파이프의 끝점과 가장 가까운 커넥터를 얻어와라. // dist = double.MaxValue; // foreach (Connector c in conns) // { // XYZ p = c.Origin; // XYZ valvept = pipe_end.Origin; // double d = p.DistanceTo(valvept); // // if (d < dist) // { // dist = d; // first = c; // } // } // // // 밸브의 커넥터중 파이프의 끝점과 가장 먼 커넥터를 찾아라. // foreach (Connector c in conns) // { // XYZ p = c.Origin; // XYZ valvept = pipe_end.Origin; // double d = p.DistanceTo(valvept); // // if (c != first) // { // second = c; // break; // } // // } // // // 커넥터를 연결해준다. // df = GetDefinition(fi, "DI"); // familyParam = fi.get_Parameter(df); // df = GetDefinition(fi.Symbol, "DI"); // familyParam = fi.Symbol.get_Parameter(df); // sw = familyParam.Set(pipe_end.Radius * 2); // pipe_end.ConnectTo(first); //} // 배수 밸브 파이프 그리기 XYZ outinpt = new XYZ(outvalveconn.Origin.X, outvalveconn.Origin.Y, (outvalveconn.Origin.Z - Unit.MMToFeet(150))); //XYZ outinpt = new XYZ(outvalveconn.Origin.X, outvalveconn.Origin.Y, (outvalveconn.Origin.Z - Unit.CovertToAPI(150, DisplayUnitType.DUT_MILLIMETERS))); //pipes = uidoc.Document.Create.NewPipe(outinpt, outvalveconn, pipeType); pipes = Pipe.Create(doc, pSysType.Id, pipeType.Id, level.Id, outvalveconn.Origin, outinpt); //파이프와 헤더 몸통 커넥터 연결 List ConLst = Util.GetElementConnectors(pipes); foreach (Connector con in ConLst) { if (con.Origin.IsAlmostEqualTo(outvalveconn.Origin, Unit.MMToFeet(0.01))) con.ConnectTo(outvalveconn); } ChangePipeSize(pipes, 32); //20210309 트랩 파이프 그리기 추가 // 트랩 파이프 그리기 XYZ trapInpt = new XYZ(trapvalveconn.Origin.X, trapvalveconn.Origin.Y, (trapvalveconn.Origin.Z - Unit.MMToFeet(150))); pipes = Pipe.Create(doc, pSysType.Id, pipeType.Id, level.Id, trapvalveconn.Origin, trapInpt); //파이프와 헤더 몸통 커넥터 연결 ConLst = Util.GetElementConnectors(pipes); foreach (Connector con in ConLst) { if (con.Origin.IsAlmostEqualTo(trapvalveconn.Origin, Unit.MMToFeet(0.01))) con.ConnectTo(trapvalveconn); } ChangePipeSize(pipes, 32); uidoc.Document.Regenerate(); trans.Commit(); } } else { throw new Exception("Couldn't load "); } } private double SL(double index1, double index2) { int i; int n; double dGet, val1, val2; HeValue heval; string s; //수정 해야 할 부분 //yong 02.12 return값에 맞춰서 excel data핸들링하게 ..... n = (int)m_ArrValue.Count(); for (i = 0; i < n; i++) { heval = m_ArrValue[i]; val1 = Convert.ToDouble(heval.he); val2 = Convert.ToDouble(heval.we); if (((Math.Abs(val1 - index1) < 0.001 && Math.Abs(val2 - index2) < 0.001) || (Math.Abs(val1 - index2) < 0.001 && Math.Abs(val2 - index1) < 0.001)) && (val1 != 0.0f && val2 != 0.0f)) { dGet = Convert.ToDouble(heval.val); return dGet; break;// } } //////////////////////////// return 0.0f; } // defun-end private void FL(double index) { HdValue val; double dHDDIA; //HDDIA,BLTSIZE,BLTBORE,BLTNO,FLGID,BLTCENDST,FLGOD //헤더지름,볼트 사이즈,구멍크기,구멍개수,플랜지 내경,볼트 중심간 거리 ,플랜지 외경 for (int i = 0; i < m_ArrHdValue.Count; i++) { val = m_ArrHdValue[i]; dHDDIA = Convert.ToDouble(val.HDDIA); if (dHDDIA == index) { flst[0] = dHDDIA; flst[1] = Convert.ToDouble(val.BLTSIZE); flst[2] = Convert.ToDouble(val.BLTBORE); flst[3] = Convert.ToDouble(val.BLTNO); flst[4] = Convert.ToDouble(val.FLGID); flst[5] = Convert.ToDouble(val.BLTCENDST); flst[6] = Convert.ToDouble(val.FLGOD); return; } } } //defun-end private int HDR_2D(double hd2, double chg2) { double dd1, dd2, dd3; dd1 = 0.28 * hd2; dd2 = 0.44 * hd2; dd3 = 0.28 * hd2; if (dd2 > chg2) return 0; else { gd_List[0] = dd1; gd_List[1] = dd2; gd_List[2] = dd3; return 2; } } // defun hdr-2d private int HDR_3D(double hd2, double chg2) { double dd1, dd2, dd3, dd4; dd1 = 0.13 * hd2; dd2 = 0.37 * hd2; dd3 = 0.37 * hd2; dd4 = 0.13 * hd2; if (dd2 > chg2) return 0; else { gd_List[0] = dd1; gd_List[1] = dd2; gd_List[2] = dd3; gd_List[3] = dd4; return 3; } } // defun hdr-3d private int HDR_4D(double hd2, double chg2) { double dd1, dd2, dd3, dd4, dd5; dd1 = 0.095 * hd2; dd2 = 0.27 * hd2; dd3 = 0.27 * hd2; dd4 = 0.27 * hd2; dd5 = 0.095 * hd2; if (dd2 > chg2) return 0; else { gd_List[0] = dd1; gd_List[1] = dd2; gd_List[2] = dd3; gd_List[3] = dd4; gd_List[4] = dd5; return 4; } } // defun hdr-4d private int HDR_5D(double hd2, double chg2) { double dd1, dd2, dd3, dd4, dd5, dd6; dd1 = 0.08 * hd2; dd2 = 0.21 * hd2; dd3 = 0.21 * hd2; dd4 = 0.21 * hd2; dd5 = 0.21 * hd2; dd6 = 0.08 * hd2; if (dd2 > chg2) return 0; else { gd_List[0] = dd1; gd_List[1] = dd2; gd_List[2] = dd3; gd_List[3] = dd4; gd_List[4] = dd5; gd_List[5] = dd6; return 5; } } // defun hdr-2d // 패밀리 존재 여부 검토 private List getFamily(string categori) { List familySymbol = new List(); List fiCreationDatas = new List(); ElementSet elementSet = null; //Try to get a FamilySymbol FilteredElementCollector collector = new FilteredElementCollector(m_revit.Application.ActiveUIDocument.Document); ICollection collection = collector.OfClass(typeof(FamilySymbol)).ToElements(); FamilySymbol Symbol; foreach (Element e in collection) { Symbol = e as FamilySymbol; if (null != Symbol.Category) { if (categori == Symbol.Category.Name) { familySymbol.Add(Symbol); } } } return familySymbol; } // 패밀리 존재 여부 검토 private FamilySymbol getNameByFamily(string name) { List fiCreationDatas = new List(); ElementSet elementSet = null; //Try to get a FamilySymbol FilteredElementCollector collector = new FilteredElementCollector(m_revit.Application.ActiveUIDocument.Document); 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 Tmp = System.Reflection.Assembly.GetExecutingAssembly().Location; //Tmp = Tmp.Replace("\\KMBIM2019.dll", ""); string Tmp = Util.GetKMBIMLibraryFolder("Libraries\\Header"); // get the active view's level for beam creation Level level = uidoc.Document.GetElement(uidoc.ActiveView.LevelId) as Level; // load a family symbol from file FamilySymbol gotSymbol = null; String fileName = Tmp + famroot;// "\\data\\2010-0240312-글로브_밸브_(플랜지형).rfa"; // 아래의 이름은 패밀리 고유의 이름이다. 패밀리 작업할때 입력하게 되어있다. String name = famname;//"2010-0240312-글로브_밸브_(플랜지형)"; FamilyInstance instance = null; // 패밀리를 로드한다. Family fam = null; ElementType elemType = null; //uidoc.Document.LoadFamilySymbol(fileName, "", out gotSymbol); bool sw = uidoc.Document.LoadFamily(fileName, out fam); if (sw == true) { /*foreach (FamilySymbol c in fam.Symbols) { gotSymbol = c; }*/ 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; } private FamilySymbol LoadFamilys(string FamilyPath) { // get the active view's level for beam creation Level level = uidoc.Document.GetElement(uidoc.ActiveView.LevelId) as Level; // load a family symbol from file FamilySymbol gotSymbol = null; String fileName = FamilyPath;// "\\data\\2010-0240312-글로브_밸브_(플랜지형).rfa"; // 아래의 이름은 패밀리 고유의 이름이다. 패밀리 작업할때 입력하게 되어있다. String name = Path.GetFileNameWithoutExtension(FamilyPath);//"2010-0240312-글로브_밸브_(플랜지형)"; // 패밀리를 로드한다. Family fam = null; bool sw = uidoc.Document.LoadFamily(fileName, out fam); 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; } /// /// 매개 변수 정의를 반환합니다. /// 주어진 요소와 매개 변수 이름. /// 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 void ChangePipeSize(Pipe pipe, double bore) { Parameter parameter = pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); // string message = "Pipe diameter: " + parameter.AsValueString(); parameter.Set(Unit.MMToFeet(bore)); // set to 6" //parameter.Set(Unit.CovertToAPI(bore, DisplayUnitType.DUT_MILLIMETERS)); // set to 6" // message += "\nPipe diameter after set: " + parameter.AsValueString(); //MessageBox.Show(message, "Revit"); } } }