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 Autodesk.Revit.DB.Plumbing; using KDCS.Utils; using Autodesk.Revit.DB.Structure; using KMBIM.Revit.Tools.Cmd.SprinklerConnect; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] class PipeTrimSpacing : 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) { 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 { //commandData.Application.ActiveUIDocument.Selection.PickBox(PickBoxStyle.Crossing) //List m_SelectLst = Util.GetSelectedElements(uidoc); //if (m_SelectLst.Count == 0) //{ // MessageBox.Show("이 명령을 실행하기 전에 배치할 파이프를 선택해야 합니다."); // return Result.Succeeded; //} //else //{ // foreach(Element e in m_SelectLst) // { // if(e is Pipe) // { // m_ElemLst.Add(e); // } // } // //} 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); } Reference pickref = commandData.Application.ActiveUIDocument.Selection.PickObject(ObjectType.Element, new SelectionFilter(), "기준 배관 선택 : "); if (pickref == null) return Result.Cancelled; //기준 배관 선택. Element pickelem = doc.GetElement(pickref.ElementId); Connector DirCon = null; if(pickelem != null) { Connector SpCon = null, EpCon = null; Pipe DirPipe = pickelem as Pipe; Util.GetStartEndConnector(DirPipe, ref SpCon, ref EpCon); //기준 배관의 끝쪽 구하기. if (SpCon.IsConnected == false && EpCon.IsConnected == true) DirCon = SpCon; else if (SpCon.IsConnected == true && EpCon.IsConnected == false) DirCon = EpCon; else if (SpCon.IsConnected == false && EpCon.IsConnected == false) DirCon = SpCon; else if(SpCon.IsConnected == true && EpCon.IsConnected == true) { Connector NextSpCon = Util.GetNextElementConnector(SpCon); Connector NextEpCon = Util.GetNextElementConnector(EpCon); if (Util.GetFamilyPartType(NextSpCon, PartType.Cap) == true || Util.GetFamilyPartType(NextSpCon, PartType.EndCap) == true) { DirCon = SpCon; } else if (Util.GetFamilyPartType(NextEpCon, PartType.Cap) == true || Util.GetFamilyPartType(NextEpCon, PartType.EndCap) == true) { DirCon = EpCon; } else//말단부가 아닌 파이프 선택시 선택한 파이프의 시작점을 기준점으로 잡음 { DirCon = SpCon; } } } Form_TrimSpacing dlg = new Form_TrimSpacing(); //라벨 m / 길이 : 6 변경 dlg.m_label = "m"; dlg.m_trimDist = 6; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.Cancel) return Result.Cancelled; //대화상자 값 가져오기 m_TrimDist = Math.Round(dlg.m_trimDist); Pipe pp = pickelem as Pipe; var aa = pp.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH); double bb = Unit.FeetToMM(aa.AsDouble()); Curve cr = (pp.Location as LocationCurve).Curve; double cc = Unit.FeetToMM(cr.Length); 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; if (elem is Pipe) { Util.GetStartEndPoint(elem as Pipe, ref sp, ref ep); //현재 파이프 시작,끝 커넥터 중 기준 커넥터와 가까운 커넥터를 sp, 먼 커넥터를 ep로 변경 if (DirCon.Origin.DistanceTo(sp) > DirCon.Origin.DistanceTo(ep)) { XYZ passPt = sp; sp = ep; ep = passPt; } Line pipeline = ((elem as Pipe).Location as LocationCurve).Curve as Line; FlowVec = (ep - sp).Normalize(); //XYZ trimPt = Util.Polar(sp, FlowVec, Unit.MMToFeet(m_TrimDist * 1000)); XYZ trimPt = Util.Polar(sp, FlowVec, Unit.MMToFeet(m_TrimDist * 1000)); int Cnt = 1; while (true) { IntersectionResult interRes = pipeline.Project(trimPt); XYZ interResPt = interRes.XYZPoint; //Util.Pyosi(doc, interResPt, 1); //MessageBox.Show("1"); //interRes가 선의 끝점부터 if (interResPt.IsAlmostEqualTo(trimPt, Unit.MMToFeet(0.01))) { m_DivPtLst.Add(interResPt); //피팅 Connector resCon = FittingUnion(elem, interResPt, m_TrimDist, ref NotDrawCnt); if (resCon == null) break; //trimPt = Util.Polar(resCon.Origin, FlowVec, Unit.MMToFeet(m_TrimDist * 1000)); trimPt = Util.Polar(resCon.Origin, FlowVec, Unit.MMToFeet(m_TrimDist * 1000)); } else break; Cnt++; }//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 { Pipe mainPipe = elem as Pipe; Connector mainspCon = null, mainepCon = null; Util.GetStartEndConnector(mainPipe, ref mainspCon, ref mainepCon); if(divPt.DistanceTo(mainspCon.Origin) ElemIDLst = Util.DivideElement(doc, mainPipe, divPt); if (ElemIDLst != null) { //List famconlst = Util.GetElementConnectors(newFamily); List pipe1conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst.First())); List pipe2conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst[1])); if (pipe1conlst[0].Origin.IsAlmostEqualTo(pipe1conlst[1].Origin, Unit.MMToFeet(0.01)) || pipe2conlst[0].Origin.IsAlmostEqualTo(pipe2conlst[1].Origin, Unit.MMToFeet(0.01))) { NotDrawCnt++; return null; } //자른 객체의 겹치는 커넥터에 유니온 피팅 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); if (famUnion != null) { 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 Pipe, ref Fsp, ref Fep); Util.GetStartEndConnector(doc.GetElement(ElemIDLst[1]) as Pipe, 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 * 1000)) > Unit.MMToFeet(0.01)) { if (Fsp.Origin.DistanceTo(Fep.Origin) - Unit.MMToFeet(TrimDist * 1000) < 0) { /*유니온 두개의 커넥터 사이기 길이 반만큼 이동해야 하기 때문에 뒤쪽 파이프 시작점으로 이동*/ XYZ translation = Ssp.Origin - familyTrans.Origin; ElementTransformUtils.MoveElement(doc, famUnion.Id, translation); doc.Regenerate(); //위치 변경 후 뒤쪽 파이프 시작점 리턴(시작점부터 다시 지정값만큼 이동해야 해서) Util.GetStartEndConnector(doc.GetElement(ElemIDLst[1]) as Pipe, 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; } } } else NotDrawCnt++; break; } } } } } catch { return resCon; } return resCon; } public class SelectionFilter : ISelectionFilter { public bool AllowElement(Element element) { if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves) { return true; } return false; } public bool AllowReference(Reference refer, XYZ point) { return false; } } } }