using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Mechanical; using Autodesk.Revit.DB.Plumbing; using Autodesk.Revit.Creation; using Autodesk.Revit.UI.Selection; using Autodesk.Revit.DB.Structure; using System.Windows.Forms; using Autodesk.Revit.ApplicationServices; using KDCS.Utils; using KMBIM.Revit.Tools; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] class PipeRealDim : IExternalCommand { UIApplication uiapp; UIDocument uidoc; Autodesk.Revit.DB.Document doc; Autodesk.Revit.Creation.Application creApp; Autodesk.Revit.Creation.Document creDoc; Autodesk.Revit.DB.View view; ExternalCommandData m_commandData; LanguageType lang; List m_ElemIDLst = new List(); List m_MainElemIDLst1 = new List();//선택한 파이프의 시작점 방향 커넥터 모음 List m_MainElemIDLst2 = new List();//선택한 파이프의 끝점 방향 커넥터 모음 public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded; uiapp = commandData.Application; uidoc = uiapp.ActiveUIDocument; doc = uidoc.Document; m_commandData = commandData; creApp = uiapp.Application.Create; creDoc = doc.Create; view = doc.ActiveView; lang = commandData.Application.Application.Language; try { //파이프 선택 Reference pickRef = uidoc.Selection.PickObject(ObjectType.Element, new SelectionFilter(), "치수 기입할 배관 선택 : "); //Reference pipeRef = uidoc.Selection.PickObject(ObjectType.Element, "치수 기입할 배관 선택 : "); //IList refs = uidoc.Selection.PickObjects(ObjectType.Element, "치수 기입 : "); //방향 지정 XYZ directPt = null; Util.PickPoint(uidoc, "치수 방향을 지정하세요.", ref directPt); XYZ sp1 = null, ep1 = null; ConnectorSet connectorSet = new ConnectorSet(); if (pickRef == null || directPt == null) return Result.Succeeded; else { Element e = doc.GetElement(pickRef); if (e is Pipe) { Pipe pipe = doc.GetElement(pickRef) as Pipe; Util.GetStartEndPoint(pipe, ref sp1, ref ep1); //선택한 파이프의 시작점 방향 커넥터 모음에 선택파이프 추가 m_MainElemIDLst1.Add(pipe.Id); connectorSet = pipe.ConnectorManager.Connectors; } else if (e is Duct) { Duct duct = doc.GetElement(pickRef) as Duct; Util.GetStartEndPoint(duct, ref sp1, ref ep1); //선택한 파이프의 시작점 방향 커넥터 모음에 선택덕트 추가 m_MainElemIDLst1.Add(duct.Id); connectorSet = duct.ConnectorManager.Connectors; } } XYZ FlowVec = (ep1 - sp1).Normalize();//시작-끝 방향 Vector XYZ ReverseVec = (sp1 - ep1).Normalize(); // 시작-끝 역방향 Vector bool isRight = Util.isRightPoint(directPt, sp1, ep1); Connector NextCon = null; int LoopMax = 0; int ConNum = 1;//파이프 2개의 커넥터 방향 나누기 위해 foreach (Connector con in connectorSet) { Connector LoopCon = null; LoopCon = con; bool b_Elbow = false; //Pyosi(LoopCon.Origin, 1); //MessageBox.Show("loopcon"); //메인 객체의 양 끝 방향의 객체 리스트에 저장. while (true) { NextCon = GetConnected(LoopCon, ConNum, FlowVec, ReverseVec, ref b_Elbow, ref m_MainElemIDLst1, ref m_MainElemIDLst2); //다음 객체의 정,역방향 커넥터가 없거나 엘보일 경우 if (NextCon == null || b_Elbow == true) break; else LoopCon = NextCon; //Pyosi(NextCon.Origin, 1); //MessageBox.Show("nextcon"); LoopMax++; if (LoopMax > 1000) break; }//while end ConNum++; }//foreach end //선택 파이프 중심 양쪽 모인 메인관들 리스트 1개로 합침. m_MainElemIDLst2.Reverse(); m_ElemIDLst.AddRange(m_MainElemIDLst2); m_ElemIDLst.AddRange(m_MainElemIDLst1); //파이프 길이 치수 생성 using (Transaction trans = new Transaction(doc)) { trans.Start("CreateDim"); for (int i = 0; i < m_ElemIDLst.Count; i++) { Element elem = doc.GetElement(m_ElemIDLst[i]); if (elem is Pipe) { CreateDim(elem as Pipe, isRight, directPt); } else if (elem is Duct) { CreateDim(elem as Duct, isRight, directPt); } } trans.Commit(); } } catch (Exception e) { //MessageBox.Show("" + e); } return Result.Succeeded; } public void CreateDim(Pipe pipe, bool isRight, XYZ DirectPt) { SketchPlane geometryPlane = view.SketchPlane; XYZ p1 = null, p2 = null; Util.GetStartEndPoint(pipe, ref p1, ref p2); XYZ vec = null; XYZ plrpt1 = null, plrpt2 = null, p1DstPlr = null, p2DstPlr = null; bool LoopIsRight = Util.isRightPoint(DirectPt, p1, p2); XYZ chgPt = null, closePt = null; //기준 파이프의 점방향과 현재 파이프의 점방향이 다르면 sp,ep 바꾸기 if (isRight != LoopIsRight) { chgPt = p1; p1 = p2; p2 = chgPt; } p1DstPlr = Util.Polar(p1, (p1 - p2).Normalize(), 100000); p2DstPlr = Util.Polar(p2, (p2 - p1).Normalize(), 100000); if (isRight == true) { vec = Util.RotateVector(p2, p1, Util.kPi / 2); plrpt1 = Util.Polar(p1, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); plrpt2 = Util.Polar(p2, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); } else { vec = Util.RotateVector(p1, p2, Util.kPi / 2); plrpt1 = Util.Polar(p1, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); plrpt2 = Util.Polar(p2, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); } Line newLine = Line.CreateBound(plrpt1, plrpt2); Options opt = new Options(); opt.ComputeReferences = true; opt.IncludeNonVisibleObjects = true; opt.View = doc.ActiveView; ReferenceArray ra = new ReferenceArray(); GeometryElement geomElem = pipe.get_Geometry(opt); foreach (GeometryObject geoobj in geomElem) { Curve cv = geoobj as Curve; if (cv == null) continue; ra.Append(cv.GetEndPointReference(0)); ra.Append(cv.GetEndPointReference(1)); } Dimension newDim = doc.Create.NewDimension(view, newLine, ra); } public void CreateDim(Duct duct, bool isRight, XYZ DirectPt) { SketchPlane geometryPlane = view.SketchPlane; XYZ p1 = null, p2 = null; Util.GetStartEndPoint(duct, ref p1, ref p2); XYZ vec = null; XYZ plrpt1 = null, plrpt2 = null, p1DstPlr = null, p2DstPlr = null; bool LoopIsRight = Util.isRightPoint(DirectPt, p1, p2); XYZ chgPt = null, closePt = null; //기준 파이프의 점방향과 현재 파이프의 점방향이 다르면 sp,ep 바꾸기 if (isRight != LoopIsRight) { chgPt = p1; p1 = p2; p2 = chgPt; } p1DstPlr = Util.Polar(p1, (p1 - p2).Normalize(), 100000); p2DstPlr = Util.Polar(p2, (p2 - p1).Normalize(), 100000); if (isRight == true) { vec = Util.RotateVector(p2, p1, Util.kPi / 2); plrpt1 = Util.Polar(p1, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); plrpt2 = Util.Polar(p2, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); } else { vec = Util.RotateVector(p1, p2, Util.kPi / 2); plrpt1 = Util.Polar(p1, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); plrpt2 = Util.Polar(p2, vec, GetShortestDistance(DirectPt, p1DstPlr, p2DstPlr, out closePt)); } Line newLine = Line.CreateBound(plrpt1, plrpt2); Options opt = new Options(); opt.ComputeReferences = true; opt.IncludeNonVisibleObjects = true; opt.View = doc.ActiveView; ReferenceArray ra = new ReferenceArray(); foreach (var geoobj in duct.get_Geometry(opt)) { Curve cv = geoobj as Curve; if (cv == null) continue; ra.Append(cv.GetEndPointReference(0)); ra.Append(cv.GetEndPointReference(1)); } Dimension newDim = doc.Create.NewDimension(view, newLine, ra); } private double GetShortestDistance(XYZ point, XYZ listStartPoint, XYZ lineEndPoint, out XYZ closestPoint) { double dx = lineEndPoint.X - listStartPoint.X; double dy = lineEndPoint.Y - listStartPoint.Y; if ((dx == 0) && (dy == 0)) { closestPoint = listStartPoint; dx = point.X - listStartPoint.X; dy = point.Y - listStartPoint.Y; return Math.Sqrt(dx * dx + dy * dy); } double t = ((point.X - listStartPoint.X) * dx + (point.Y - listStartPoint.Y) * dy) / (dx * dx + dy * dy); if (t < 0) { closestPoint = new XYZ(listStartPoint.X, listStartPoint.Y, listStartPoint.Z); dx = point.X - listStartPoint.X; dy = point.Y - listStartPoint.Y; } else if (t > 1) { closestPoint = new XYZ(lineEndPoint.X, lineEndPoint.Y, listStartPoint.Z); dx = point.X - lineEndPoint.X; dy = point.Y - lineEndPoint.Y; } else { closestPoint = new XYZ(listStartPoint.X + t * dx, listStartPoint.Y + t * dy, listStartPoint.Z); dx = point.X - closestPoint.X; dy = point.Y - closestPoint.Y; } return Math.Sqrt(dx * dx + dy * dy); } public Connector GetConnected(Connector BaseCon, int ConNum, XYZ FlowVec, XYZ ReverseVec, ref bool b_Elbow, ref List m_ElemIDLst1, ref List m_ElemIDLst2) { //기본 커넥터 옆에 객체 구하기. Connector NextCon = GetNextConnector(BaseCon); if (NextCon == null) return null; //기본 커넥터 옆에 객체가 엘보일 경우 b_Elbow = true b_Elbow = GetFamilyPartType(NextCon, PartType.Elbow); //NextCon 객체의 정방향 또는 역방향에 위치한 커넥터 구하기. Connector resCon = GetOtherConnector(NextCon, FlowVec, ReverseVec); if (resCon != null || b_Elbow == true) { if (ConNum == 1) m_ElemIDLst1.Add(NextCon.Owner.Id); else m_ElemIDLst2.Add(NextCon.Owner.Id); } return resCon; } //패밀리의 타입구분 public bool GetFamilyPartType(Connector baseCon, PartType partType) { if (baseCon.Owner is FamilyInstance) { FamilyInstance family = baseCon.Owner as FamilyInstance; Parameter param = family.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE); if (partType == (PartType)param.AsInteger()) return true; else return false; } return false; } //NextCon 객체의 정방향 또는 역방향에 위치한 커넥터 구하기. public Connector GetOtherConnector(Connector baseCon, XYZ FlowVec, XYZ ReverseVec) { Connector resCon = null; ConnectorSet ConSet = null; MEPSystem mepSystem = baseCon.MEPSystem; FamilyInstance family = null; Pipe pipe = null; Duct duct = null; if (mepSystem != null) { if (baseCon.IsConnected == true) { if (baseCon.Owner is FamilyInstance) { family = baseCon.Owner as FamilyInstance; ConSet = family.MEPModel.ConnectorManager.Connectors; } else if (baseCon.Owner is Pipe) { pipe = baseCon.Owner as Pipe; ConSet = pipe.ConnectorManager.Connectors; } else if (baseCon.Owner is Duct) { duct = baseCon.Owner as Duct; ConSet = duct.ConnectorManager.Connectors; } foreach (Connector con in ConSet) { //입력 커넥터와 같은 커넥터는 넘긴다, if (con.Origin.IsAlmostEqualTo(baseCon.Origin, Unit.MMToFeet(0.001))) continue; else { XYZ CurVec = (con.Origin - baseCon.Origin).Normalize(); //정방향 또는 역방향 커넥터를 찾아 리턴 if (CurVec.IsAlmostEqualTo(FlowVec, Unit.MMToFeet(0.01)) || CurVec.IsAlmostEqualTo(ReverseVec, Unit.MMToFeet(0.01))) resCon = con; } } } } //Pyosi(resCon.Origin, 1); //MessageBox.Show("2"); return resCon; } //커넥터에 연결된 다음 객체의 커넥터 구하기. public Connector GetNextConnector(Connector baseCon) { Connector resCon = null; MEPSystem mepSystem = baseCon.MEPSystem; if (mepSystem != 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, Unit.MMToFeet(0.001))) { if (connected.IsConnected == true) { ConnectorSet ConnectedSet = null; FamilyInstance family = null; Pipe pipe = null; Duct duct = 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 Duct) { duct = connected.Owner as Duct; ConnectedSet = duct.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 SelectionFilter : ISelectionFilter { public bool AllowElement(Element element) { if (element.Category == null) return false; if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctCurves || element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves) { return true; } return false; } public bool AllowReference(Reference refer, XYZ point) { return false; } } } }