using System; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using System.Collections.Generic; using System.Windows.Forms; using System.Linq; using Autodesk.Revit.UI.Selection; using KDCS.Utils; using Autodesk.Revit.DB.Structure; using KMBIM.Revit.Tools.Cmd.SprinklerConnect; using Autodesk.Revit.DB.Mechanical; using KMBIM.Revit.Tools; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] class DuctTrimSpacing : 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; 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; double m_TrimDist = 0; List m_ElemLst = new List(); try { Form_TrimSpacing dlg = new Form_TrimSpacing(); //라벨 mm / 길이 : 1740 변경 dlg.m_label = "mm"; dlg.m_trimDist = 1740; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.Cancel) return Result.Cancelled; //대화상자 값 가져오기 m_TrimDist = Math.Round(dlg.m_trimDist); //IList pickrefs = commandData.Application.ActiveUIDocument.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, new SelectionFilter(), "절단할 덕트 선택 : "); //if (pickrefs == null) return Result.Cancelled; //foreach (Reference refer in pickrefs) //{ // ElementId id = refer.ElementId; // Element elem = doc.GetElement(id); // m_ElemLst.Add(elem); //} while (true) { Reference pickRef = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new SelectionFilter(), "절단할 덕트 선택 : "); XYZ Globalpt = pickRef.GlobalPoint; if (pickRef == null) return Result.Cancelled; Element elem = doc.GetElement(pickRef.ElementId); using (Transaction trans = new Transaction(doc)) { trans.Start("cutting"); XYZ sp = null, ep = null; XYZ FlowVec = null, ReverseVec = null; if (elem is Duct) { Util.GetStartEndPoint(elem as Duct, ref sp, ref ep); Line ductline = ((elem as Duct).Location as LocationCurve).Curve as Line; bool ChgSpEp = false; //끝점과 가까우면 시작 끝점 바꾸기 if (Globalpt.DistanceTo(sp) > Globalpt.DistanceTo(ep)) { XYZ PassPt = sp; sp = ep; ep = PassPt; ChgSpEp = true; } FlowVec = (ep - sp).Normalize(); ReverseVec = (sp - ep).Normalize(); XYZ DirPt = sp; Duct MainDuct = elem as Duct; double UnionLength = 0; while (true) { //자를 기준점 XYZ trimPt = Util.Polar(DirPt, FlowVec, Unit.MMToFeet(m_TrimDist)); //Util.Pyosi(doc, trimPt, 0); //자를 기준점이 파이프를 넘어간 경우 작도 중지 Line divDuctLine = (MainDuct.Location as LocationCurve).Curve as Line; XYZ onLinePt = Util.GetPointOnLine(divDuctLine, trimPt); if (onLinePt.IsAlmostEqualTo(divDuctLine.GetEndPoint(0)) || onLinePt.IsAlmostEqualTo(divDuctLine.GetEndPoint(1))) break; IntersectionResult interRes = ductline.Project(trimPt); XYZ interResPt = interRes.XYZPoint; //첫번째 유니온삽입 시 유니온 길이를 알 수 없어 50으로 정함 //두번째부터는 첫번째 넣은 유니온 길이를 구해 그 값보다 작으면 작도 X //if (trimPt.DistanceTo(ep) < Unit.MMToFeet(10)) break; if (UnionLength > 0) { if (trimPt.DistanceTo(ep) < UnionLength) break; } else { if (trimPt.DistanceTo(ep) < Unit.MMToFeet(50)) break; } List ElemIDLst = new List(); //파이프 자르기 ElemIDLst = Util.DivideElement(doc, MainDuct, trimPt); if (ElemIDLst.Count() == 0) break; //Util.Pyosi(doc, trimPt, 0); DirPt = trimPt; doc.Regenerate(); if (ChgSpEp == true) { MainDuct = doc.GetElement(ElemIDLst[0]) as Duct; } List pipe1conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst[0])); List pipe2conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst[1])); //자른 객체의 겹치는 커넥터에 유니온 피팅 foreach (Connector con1 in pipe1conlst) { foreach (Connector con2 in pipe2conlst) { if (con1.Origin.IsAlmostEqualTo(con2.Origin, Unit.MMToFeet(0.01))) { //유니온 피팅 FamilyInstance famUnion = doc.Create.NewUnionFitting(con1, con2); List UnionConLst = Util.GetElementConnectors(famUnion); if (UnionConLst.Count == 2) { UnionLength = UnionConLst[0].Origin.DistanceTo(UnionConLst[1].Origin); } //Util.Pyosi(doc, con1.Origin, 0); //DirPt = con1.Origin; doc.Regenerate(); //if (famUnion == null) NotDrawCnt++; break; } } } }//while end } trans.Commit(); } }//while end //int NotDrawCnt = 0; //using (Transaction trans = new Transaction(doc)) //{ // trans.Start("1"); // foreach (Element elem in m_ElemLst) // { // List m_DivPtLst = new List(); // XYZ sp = null, ep = null; // XYZ FlowVec = null, ReverseVec = null; // // if (elem is Duct) // { // Util.GetStartEndPoint(elem as Duct, ref sp, ref ep); // Line Ductline = ((elem as Duct).Location as LocationCurve).Curve as Line; // // FlowVec = (ep - sp).Normalize(); // ReverseVec = (sp - ep).Normalize(); // // XYZ DirPt = sp; // Duct mainDuct = elem as Duct; // // double UnionLength = 0; // while (true) // { // //자를 기준점 // XYZ trimPt = Util.Polar(DirPt, FlowVec, Unit.MMToFeet(m_TrimDist)); // //자를 기준점이 덕트를 넘어간 경우 작도 중지 // Line divDuctLine = (mainDuct.Location as LocationCurve).Curve as Line; // XYZ onLinePt = Util.GetPointOnLine(divDuctLine, trimPt); // // if (onLinePt.IsAlmostEqualTo(divDuctLine.GetEndPoint(0)) // || onLinePt.IsAlmostEqualTo(divDuctLine.GetEndPoint(1))) // break; // // IntersectionResult interRes = Ductline.Project(trimPt); // XYZ interResPt = interRes.XYZPoint; // //첫번째 유니온삽입 시 유니온 길이를 알 수 없어 50으로 정함 // //두번째부터는 첫번째 넣은 유니온 길이를 구해 그 값보다 작으면 작도 X // //if (trimPt.DistanceTo(ep) < Unit.MMToFeet(10)) break; // if (UnionLength > 0) // { // if (trimPt.DistanceTo(ep) < UnionLength) break; // } // else // { // if (trimPt.DistanceTo(ep) < Unit.MMToFeet(50)) break; // } // // //덕트 자르기 // List ElemIDLst = Util.DivideElement(doc, mainDuct, trimPt); // DirPt = trimPt; // if (ElemIDLst.Count() == 0) break; // // doc.Regenerate(); // // List duct1conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst[0])); // List duct2conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst[1])); // // // //자른 객체의 겹치는 커넥터에 유니온 피팅 // foreach (Connector con1 in duct1conlst) // { // foreach (Connector con2 in duct2conlst) // { // if (con1.Origin.IsAlmostEqualTo(con2.Origin, Unit.MMToFeet(0.01))) // { // //유니온 피팅 // FamilyInstance famUnion = doc.Create.NewUnionFitting(con1, con2); // List UnionConLst = Util.GetElementConnectors(famUnion); // if (UnionConLst.Count == 2) // { // UnionLength = UnionConLst[0].Origin.DistanceTo(UnionConLst[1].Origin); // } // //Util.Pyosi(doc, con1.Origin, 0); // //DirPt = con1.Origin; // doc.Regenerate(); // // if (famUnion == null) NotDrawCnt++; // break; // } // } // } // // }//while end // } // }//foreach end // trans.Commit(); //} // //if (NotDrawCnt > 0) // MessageBox.Show("작도 실패 : " + NotDrawCnt + " 개", "결과"); } catch (Exception) { //MessageBox.Show("" + e); } return Result.Succeeded; } /// /// 유니온 피팅 /// /// 덕트 /// 자를 점 위치 /// 1본 길이 /// 유니온 피팅 실패 갯수 /// public Connector FittingUnion(Element elem, XYZ divPt, double TrimDist, ref int NotDrawCnt) { Connector resCon = null; try { Duct mainDuct = elem as Duct; //파이프 자르기 List ElemIDLst = Util.DivideElement(doc, mainDuct, divPt); if (ElemIDLst != null) { //List famconlst = Util.GetElementConnectors(newFamily); List Duct1conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst.First())); List Duct2conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst[1])); if (Duct1conlst[0].Origin.IsAlmostEqualTo(Duct1conlst[1].Origin, Unit.MMToFeet(0.01))) return null; if (Duct2conlst[0].Origin.IsAlmostEqualTo(Duct2conlst[1].Origin, Unit.MMToFeet(0.01))) return null; //자른 객체의 겹치는 커넥터에 유니온 피팅 foreach (Connector con1 in Duct1conlst) { foreach (Connector con2 in Duct2conlst) { if (con1.Origin.IsAlmostEqualTo(con2.Origin, Unit.MMToFeet(0.01))) { //유니온 피팅 FamilyInstance famUnion = doc.Create.NewUnionFitting(con1, con2); Transform familyTrans = famUnion.GetTransform(); List famConLst = Util.GetElementConnectors(famUnion); doc.Regenerate(); Connector Fsp = null, Fep = null, Ssp = null, Sep = null; Util.GetStartEndConnector(doc.GetElement(ElemIDLst.First()) as Duct, ref Fsp, ref Fep); Util.GetStartEndConnector(doc.GetElement(ElemIDLst[1]) as Duct, ref Ssp, ref Sep); //유니온 장착 후 앞쪽 파이프 길이가 지정한 길이가 아니면 유니온 옮김 //if (Math.Abs(Fsp.Origin.DistanceTo(Fep.Origin) - Unit.MMToFeet(TrimDist * 1000)) > Unit.MMToFeet(0.01)) if (Math.Abs(Fsp.Origin.DistanceTo(Fep.Origin) - Unit.MMToFeet(TrimDist)) > Unit.MMToFeet(0.01)) { if (Fsp.Origin.DistanceTo(Fep.Origin) - Unit.MMToFeet(TrimDist) < 0) { /*유니온 두개의 커넥터 사이기 길이 반만큼 이동해야 하기 때문에 뒤쪽 파이프 시작점으로 이동*/ XYZ translation = Ssp.Origin - familyTrans.Origin; ElementTransformUtils.MoveElement(doc, famUnion.Id, translation); doc.Regenerate(); //위치 변경 후 뒤쪽 파이프 시작점 리턴(시작점부터 다시 지정값만큼 이동해야 해서) Util.GetStartEndConnector(doc.GetElement(ElemIDLst[1]) as Duct, ref Ssp, ref Sep); //절단 길이 + 유니온 이동거리 > 남은 파이프 길이 = return //if (Unit.MMToFeet(TrimDist * 1000) + (Ssp.Origin.DistanceTo(familyTrans.Origin)*3) // > Ssp.Origin.DistanceTo(Sep.Origin)) return null; resCon = Ssp; break; } } if (famUnion == null) NotDrawCnt++; break; } } } } } catch { return resCon; } return resCon; } public class SelectionFilter : ISelectionFilter { public bool AllowElement(Element element) { if (element.Category == null) return false; if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctCurves) { return true; } return false; } public bool AllowReference(Reference refer, XYZ point) { return false; } } } }