using System; using System.Collections.Generic; using System.Linq; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Plumbing; using System.Windows.Forms; using Autodesk.Revit.DB.Mechanical; using KDCS.Utils; namespace KMBIM { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] class PartSpacing : 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; public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { uiapp = commandData.Application; uidoc = uiapp.ActiveUIDocument; doc = uidoc.Document; m_commandData = commandData; creApp = uiapp.Application.Create; creDoc = doc.Create; view = doc.ActiveView; bool b_Cap = false, b_Reducer = false; double m_Dist = 0; List m_SelElemLst = new List(); List m_SelTeeLst = new List(); List m_SelRDCLst = new List(); List m_SelCapLst = new List(); try { MainForm dlg = new MainForm(); dlg.Dist = 100; dlg.Cap = true; dlg.Reducer = true; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.Cancel) return Result.Succeeded; b_Cap = dlg.Cap; b_Reducer = dlg.Reducer; m_Dist = dlg.Dist; IList pickrefs = commandData.Application.ActiveUIDocument.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element); //선택한 객체들 Element로 리스트에 저장 if (pickrefs != null) { foreach (Reference refer in pickrefs) { ElementId elemID = refer.ElementId; Element selElem = doc.GetElement(elemID); m_SelElemLst.Add(selElem); } } else return Result.Succeeded; ////선택된 객체중 패밀리 TEE를 리스트에 모음. //foreach (Element e in m_SelElemLst) //{ // if (e is FamilyInstance) // { // FamilyInstance family = e as FamilyInstance; // var param = family.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE); // if ((PartType)param.AsInteger() == PartType.Tee) // m_SelTeeLst.Add(family); // // } //} //Reference reference = commandData.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element); //Element selElem2 = doc.GetElement(reference); //List m_sideElement = new List(); // //foreach (Element Tee in m_SelTeeLst) //{ // GetSideElement(Tee, ref m_sideElement); //} //foreach (FamilyInstance family in m_SelTeeLst) //{ // ConnectorSet conSet = family.MEPModel.ConnectorManager.Connectors; // foreach (Connector con in conSet) // { // Pyosi(con.Origin, 1); // MessageBox.Show("1"); // break; // } //} //선택된 객체중 패밀리 레듀셔,캡을 리스트에 모음. foreach (Element e in m_SelElemLst) { if (e is FamilyInstance) { FamilyInstance family = e as FamilyInstance; var param = family.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE); if ((PartType)param.AsInteger() == PartType.Transition) m_SelRDCLst.Add(family); else if ((PartType)param.AsInteger() == PartType.Cap) m_SelCapLst.Add(family); } } if (b_Reducer) { foreach (Element Reducer in m_SelRDCLst) { Set_Reducer_Distance(Reducer, m_Dist); } } if (b_Cap) { foreach (Element Cap in m_SelCapLst) { Set_Cap_Distance(Cap, m_Dist); } } } catch (Exception e) { //MessageBox.Show("" + e); } return Result.Succeeded; } public void Set_Cap_Distance(Element Elem, double Dist) { if (Elem is FamilyInstance) { ConnectorSet FamilyConSet = (Elem as FamilyInstance).MEPModel.ConnectorManager.Connectors; Connector BaseCon = null; //캡은 커넥터가 하나이기 때문에 바로 BaseCon으로 지정. foreach (Connector con in FamilyConSet) { BaseCon = con; } //캡 커넥터에 붙은 객체 커넥터 Connector NextCon = GetNextElementConnector(BaseCon); if (NextCon.Owner is FamilyInstance) { } else if (NextCon.Owner is Pipe) { //파이프 반대쪽 커넥터 Connector NextOtherCon = GetOtherConnector(NextCon); //캡에 붙은 파이프 커넥터 ->파이프 반대 커넥터 방향 XYZ DirecPt = (NextOtherCon.Origin - NextCon.Origin).Normalize(); XYZ sp_pipe = null, ep_pipe = null; Util.GetStartEndPoint(NextCon.Owner as Pipe, ref sp_pipe, ref ep_pipe); double PipeDist = sp_pipe.DistanceTo(ep_pipe); MoveElement(doc, BaseCon.Owner as FamilyInstance, NextCon.Origin, DirecPt, Unit.FeetToMM(PipeDist) - Dist); } } } // Reducer 간격 맞추기. public void Set_Reducer_Distance(Element Elem, double Dist) { if (Elem is FamilyInstance) { ConnectorSet FamilyConSet = (Elem as FamilyInstance).MEPModel.ConnectorManager.Connectors; List m_ElemConLst = Util.GetElementConnectors(Elem); //레듀셔의 큰쪽을 Base로 작업 //레듀셔 큰->작은 방향 Connector BaseCon = null; Connector OtherCon = null; XYZ DirecPt = null; if (m_ElemConLst.Count == 2) { if (m_ElemConLst[0].Radius > m_ElemConLst[1].Radius) { BaseCon = m_ElemConLst[0]; DirecPt = (m_ElemConLst[1].Origin - m_ElemConLst[0].Origin).Normalize(); OtherCon = m_ElemConLst[1]; } else { BaseCon = m_ElemConLst[1]; DirecPt = (m_ElemConLst[0].Origin - m_ElemConLst[1].Origin).Normalize(); OtherCon = m_ElemConLst[0]; } } //T와 레듀셔 사이에 기존 파이프 타입을 가져오기위해 주변에서 파이프 찾기. Connector OtherNextCon = GetNextElementConnector(OtherCon); Pipe pipe = null; if (OtherNextCon.Owner is Pipe) { pipe = OtherNextCon.Owner as Pipe; } if (BaseCon.IsConnected == true) { //레듀셔 커넥터에 연결된 다음 객체 커넥터 구하기 Connector NextCon = GetNextElementConnector(BaseCon); if (NextCon.Owner is FamilyInstance)//레듀셔 옆이 패밀리인가 { if (GetFamilyPartType(NextCon, PartType.Elbow) || GetFamilyPartType(NextCon, PartType.Tee)) { //레듀셔와 엘보 또는 티 커넥터 끊기 using (Transaction trans = new Transaction(doc)) { trans.Start("DisConnect"); BaseCon.DisconnectFrom(NextCon); MoveElement(doc, BaseCon.Owner as FamilyInstance, BaseCon.Origin, DirecPt, Dist); Level level = new FilteredElementCollector(doc).OfClass(typeof(Level)).First() as Level; Pipe newPipe = Pipe.Create(doc, pipe.GetTypeId(), pipe.LevelId, BaseCon, NextCon); trans.Commit(); } } //레듀셔 작은쪽에 붙은 객체 커넥터 Connector RedNextOtherCon = GetNextElementConnector(OtherCon); if (GetFamilyPartType(NextCon, PartType.Elbow) || GetFamilyPartType(NextCon, PartType.Tee)) { //레듀셔와 엘보 또는 티 커넥터 끊기 using (Transaction trans = new Transaction(doc)) { trans.Start("DisConnect"); OtherCon.DisconnectFrom(RedNextOtherCon); MoveElement(doc, OtherCon.Owner as FamilyInstance, OtherCon.Origin, DirecPt, Dist); Level level = new FilteredElementCollector(doc).OfClass(typeof(Level)).First() as Level; Pipe newPipe = Pipe.Create(doc, pipe.GetTypeId(), pipe.LevelId, OtherCon, RedNextOtherCon); trans.Commit(); } } } else if (NextCon.Owner is Pipe)//레듀셔 옆이 파이프인가 { Connector NextOtherCon = GetOtherConnector(NextCon); Connector NextCon2 = GetNextElementConnector(NextOtherCon); if (NextCon2.Owner is FamilyInstance) { if (GetFamilyPartType(NextCon2, PartType.Elbow) || GetFamilyPartType(NextCon2, PartType.Tee)) { XYZ sp_pipe = null, ep_pipe = null; Util.GetStartEndPoint(NextCon.Owner as Pipe, ref sp_pipe, ref ep_pipe); double PipeDist = sp_pipe.DistanceTo(ep_pipe); MoveElement(doc, BaseCon.Owner as FamilyInstance, NextCon.Origin, DirecPt, Dist - Unit.FeetToMM(PipeDist)); } } } } } } //Element 커넥터에 붙어있는 객체를 구하는 함수 public void GetSideElement(Element Elem, ref List m_SideElements) { ConnectorSet ElemConSet = null; if (Elem is FamilyInstance) ElemConSet = (Elem as FamilyInstance).MEPModel.ConnectorManager.Connectors; else if (Elem is Pipe) ElemConSet = (Elem as Pipe).ConnectorManager.Connectors; else if (Elem is Duct) ElemConSet = (Elem as Duct).ConnectorManager.Connectors; foreach (Connector ElemCon in ElemConSet)//Tee 커넥터 { if (ElemCon.MEPSystem != null) { if (ElemCon.IsConnected == true) { //현재 커넥터에 연결된 다음 객체의 커넥터 구하기 Connector NextCon = GetNextElementConnector(ElemCon); if (NextCon == null) continue; if (NextCon.Owner is FamilyInstance) { bool tf = GetFamilyPartType(NextCon, PartType.Transition); if (tf)//레듀셔일 때 { //Pyosi(NextCon.Origin, 1); //MessageBox.Show("1"); //현재 커넥터의 객체가 커넥터가 2개일 때 현재 커넥터의 반대쪽 커넥터 구하기. Connector NextOtherCon1 = GetOtherConnector(NextCon); if (NextCon.Radius < NextOtherCon1.Radius) continue; FamilyInstance m_Reducer = NextCon.Owner as FamilyInstance; //레듀셔 옆 파이프 또는 덕트 커넥터 구하기 Connector NextOtherCon2 = GetNextElementConnector(NextOtherCon1); if (NextOtherCon2 == null) continue; //Tee와 레듀셔의 교차 커넥터 끊기 using (Transaction trans = new Transaction(doc)) { trans.Start("DisConnect"); ElemCon.DisconnectFrom(NextCon); trans.Commit(); } //Pyosi(NextCon.Origin, 1); //MessageBox.Show("1"); //Pyosi(NextOtherCon1.Origin, 1); //MessageBox.Show("2"); //Tee에 연결된 레듀셔의 커넥터에서 - 레듀셔 방향 XYZ VecPt = (NextOtherCon1.Origin - NextCon.Origin).Normalize(); //레듀셔 위치 조정 MoveElement(doc, NextCon.Owner as FamilyInstance, NextCon.Origin, VecPt, 200); if (NextOtherCon2.Owner is Pipe) { Pipe pipe = NextOtherCon2.Owner as Pipe; using (Transaction trans = new Transaction(doc)) { trans.Start("CreatePipe"); Level level = new FilteredElementCollector(doc).OfClass(typeof(Level)).First() as Level; Pipe newPipe = Pipe.Create(doc, pipe.GetTypeId(), pipe.LevelId, ElemCon, NextCon); trans.Commit(); } } } else { } } else if (NextCon.Owner is Pipe || NextCon.Owner is Duct) { //현재 커넥터의 객체가 커넥터가 2개일 때 현재 커넥터의 반대쪽 커넥터 구하기. Connector NextOtherCon1 = GetOtherConnector(NextCon); Pipe pipe = null; Duct duct = null; if (NextCon.Owner is Pipe) { //Pyosi(NextCon.Origin, 1); //MessageBox.Show("NextCon"); pipe = NextCon.Owner as Pipe; //파이프 옆 패밀리 커넥터 구하기 Connector familyCon = GetNextElementConnector(NextOtherCon1); if (familyCon == null) continue; //Pyosi(familyCon.Origin, 1); //MessageBox.Show("familyCon"); bool tf = GetFamilyPartType(familyCon, PartType.Transition); if (tf) { //현재 커넥터의 객체가 커넥터가 2개일 때 현재 커넥터의 반대쪽 커넥터 구하기. Connector familyOtherCon = GetOtherConnector(familyCon); if (familyCon.Radius < familyOtherCon.Radius) continue; //Pyosi(familyOtherCon.Origin, 1); //MessageBox.Show("familyOtherCon"); FamilyInstance m_Reducer = familyOtherCon.Owner as FamilyInstance; Connector NextOtherCon2 = GetNextElementConnector(familyOtherCon); if (NextOtherCon2 == null) continue; //Pyosi(NextOtherCon2.Origin, 1); //MessageBox.Show("NextOtherCon2"); XYZ VecPt = (NextCon.Origin - NextOtherCon1.Origin).Normalize(); double PipeDist = NextOtherCon1.Origin.DistanceTo(NextCon.Origin); //레듀셔 위치 조정 MoveElement(doc, familyCon.Owner as FamilyInstance, NextCon.Origin, VecPt, Unit.FeetToMM(PipeDist) - 200); if (NextOtherCon2.Owner is Pipe) { Pipe pipe2 = NextOtherCon2.Owner as Pipe; //NextOtherCon2.Origin } } } else if (NextCon.Owner is Duct) { duct = NextCon.Owner as Duct; //덕트 옆 패밀리 커넥터 구하기 Connector NextOtherCon2 = GetNextElementConnector(NextOtherCon1); } } //Pyosi(aa.Origin,1); //MessageBox.Show("1"); } } } } //객체 이동 함수 public void MoveElement(Autodesk.Revit.DB.Document doc, FamilyInstance family, XYZ BasePt, XYZ VecPt, double mm_MoveDist) { LocationPoint familyLoc = family.Location as LocationPoint; //polar점 구하기. XYZ plrPt = Util.Polar(BasePt, VecPt, Unit.MMToFeet(mm_MoveDist)); //커넥터 점과 Polar로 구한점을 빼 이동할 거리 만들기. XYZ NewPt = new XYZ(plrPt.X - BasePt.X, plrPt.Y - BasePt.Y, plrPt.Z - BasePt.Z); //Pyosi(NewPt, 1); //MessageBox.Show("1"); ElementTransformUtils.MoveElement(doc, family.Id, NewPt); familyLoc = family.Location as LocationPoint; XYZ newActual = familyLoc.Point; } //패밀리의 타입구분 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; } //객체의 다른 커넥터 구하기.(객체의 커넥터가 2개일 때.) public Connector GetOtherConnector(Connector baseCon) { 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))) { //Pyosi(con.Origin, 1); //MessageBox.Show("1"); continue; } else { //Pyosi(con.Origin, 1); //MessageBox.Show("2"); resCon = con; } } } } //Pyosi(resCon.Origin, 1); //MessageBox.Show("2"); return resCon; } //커넥터에 연결된 다음 객체의 커넥터 구하기. public Connector GetNextElementConnector(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 } } //Pyosi(resCon.Origin, 1); //MessageBox.Show("1"); return resCon; } public bool Pyosi(XYZ pt, int TranMode) { if (TranMode == 0) { XYZ pt1 = new XYZ(pt.X - 0.328084, pt.Y + 0.328084, pt.Z); XYZ pt2 = new XYZ(pt.X + Unit.CovertToAPI(100, DisplayUnitType.DUT_MILLIMETERS), pt.Y + Unit.CovertToAPI(100, DisplayUnitType.DUT_MILLIMETERS), pt.Z); XYZ pt3 = new XYZ(pt.X + 0.328084, pt.Y - 0.328084, pt.Z); XYZ pt4 = new XYZ(pt.X - 0.328084, pt.Y - 0.328084, pt.Z); Autodesk.Revit.DB.View view = doc.ActiveView; Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pt1, pt3); Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pt2, pt4); } else { using (Transaction transaction = new Transaction(doc)) { transaction.Start("Start"); XYZ pt1 = new XYZ(pt.X - 0.328084, pt.Y + 0.328084, pt.Z); XYZ pt2 = new XYZ(pt.X + Unit.CovertToAPI(100, DisplayUnitType.DUT_MILLIMETERS), pt.Y + Unit.CovertToAPI(100, DisplayUnitType.DUT_MILLIMETERS), pt.Z); XYZ pt3 = new XYZ(pt.X + 0.328084, pt.Y - 0.328084, pt.Z); XYZ pt4 = new XYZ(pt.X - 0.328084, pt.Y - 0.328084, pt.Z); Autodesk.Revit.DB.View view = doc.ActiveView; Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pt1, pt3); Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pt2, pt4); transaction.Commit(); } } return true; } } }