Client/Desktop/KMBIM3.0/KMBIM3.0_23.08.16_수정최종/Cmd/PartSpacing/PartSpacing.cs

720 lines
32 KiB
C#

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;
using KMBIM.Revit.Tools;
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;
ElementId PipeTypeId = null;
ElementId PipeSystemTypeId = null;
ElementId PipeLevelId = null;
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;
bool b_Cap = false, b_Reducer = false;
double m_Dist = 0;
List<Element> m_SelElemLst = new List<Element>();
List<FamilyInstance> m_SelTeeLst = new List<FamilyInstance>();
List<FamilyInstance> m_SelRDCLst = new List<FamilyInstance>();
List<FamilyInstance> m_SelCapLst = new List<FamilyInstance>();
try
{
MainForm dlg = new MainForm();
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<Reference> 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;
//선택된 객체중 패밀리 레듀셔,캡을 리스트에 모음.
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);
using(Transaction trans = new Transaction(doc))
{
trans.Start("Cap");
MoveElement(doc, BaseCon.Owner, NextCon.Origin, DirecPt, Unit.FeetToMM(PipeDist) - Dist);
trans.Commit();
}
}
}
}
// Reducer 간격 맞추기.
public void Set_Reducer_Distance(Element Elem, double Dist)
{
try
{
if (Elem is FamilyInstance)
{
List<Connector> m_ElemConLst = Util.GetElementConnectors(Elem);
//파이프 타입 찾기 위해 근처 파이프 찾기
Connector cntr = null; m_ElemConLst.First();
foreach (Connector con in m_ElemConLst)
{
cntr = con;
while (true)
{
Connector Nextcntr = Util.GetNextElementConnector(cntr);
if (Nextcntr == null) break;
if (Nextcntr.Owner is Pipe)
{
Pipe pp = Nextcntr.Owner as Pipe;
PipeSystemTypeId = pp.MEPSystem.GetTypeId();
PipeTypeId = pp.PipeType.Id;
PipeLevelId = pp.ReferenceLevel.Id;
break;
}
Connector NextOtherCntr = Util.GetOtherConnector(Nextcntr);
if (NextOtherCntr == null) break;
cntr = NextOtherCntr;
}//while end
}
//레듀셔의 큰쪽을 Base로 작업
//레듀셔 큰->작은 방향
Connector WideCon = null;
Connector narrowCon = null;
if (m_ElemConLst.Count == 2)
{
if (m_ElemConLst[0].Radius > m_ElemConLst[1].Radius)
{
WideCon = m_ElemConLst[0];
narrowCon = m_ElemConLst[1];
}
else
{
WideCon = m_ElemConLst[1];
narrowCon = m_ElemConLst[0];
}
}
double Wide2FamDist = 0;
double Narrow2FamDist = 0;
//레듀셔 관경 큰쪽에 붙은 객체
Connector WideNextCon = Util.GetNextElementConnector(WideCon);
if (WideNextCon.Owner is FamilyInstance)
{
Wide2FamDist = WideCon.Origin.DistanceTo(WideNextCon.Origin);
}
else if (WideNextCon.Owner is Pipe)
{
Connector PipeOtherCon = Util.GetOtherConnector(WideNextCon);
Connector NextFamilyCon = Util.GetNextElementConnector(PipeOtherCon);
Wide2FamDist = WideCon.Origin.DistanceTo(NextFamilyCon.Origin);
}
//레듀셔 관경 작은쪽에 붙은 객체
Connector NarrowNextCon = Util.GetNextElementConnector(narrowCon);
if (NarrowNextCon.Owner is FamilyInstance)
{
Narrow2FamDist = narrowCon.Origin.DistanceTo(NarrowNextCon.Origin);
}
else if (NarrowNextCon.Owner is Pipe)
{
Connector PipeOtherCon = Util.GetOtherConnector(NarrowNextCon);
Connector NextFamilyCon = Util.GetNextElementConnector(PipeOtherCon);
if (NextFamilyCon != null)
Narrow2FamDist = narrowCon.Origin.DistanceTo(NextFamilyCon.Origin);
else
Narrow2FamDist = narrowCon.Origin.DistanceTo(PipeOtherCon.Origin);
}
//큰 관경부터 패밀리까지 거리와 작은 관경부터 패밀리까지 거리의 합보다
//간격 조정 거리 X 2가 더크면 작도 안함.
if (Wide2FamDist + Narrow2FamDist < Unit.MMToFeet(Dist*2)) return;
//거리가 좁은쪽으로 작업
if (Wide2FamDist > Narrow2FamDist)//관경 좁은쪽 작업
{
if (NarrowNextCon.Owner is FamilyInstance)
{
using (Transaction trans = new Transaction(doc))
{
trans.Start("MoveEndCreate");
//레듀셔와 패밀리 커넥터 끊기
narrowCon.DisconnectFrom(NarrowNextCon);
XYZ Vec = (WideCon.Origin - narrowCon.Origin).Normalize();
MoveElement(doc, narrowCon.Owner, narrowCon.Origin, Vec, Dist);
// trans.Commit();
//}
//
//using (Transaction trans = new Transaction(doc))
//{
// trans.Start("CreatePipe");
Pipe newPipe = Pipe.Create(doc, PipeSystemTypeId, PipeTypeId, PipeLevelId, narrowCon.Origin, NarrowNextCon.Origin);
List<Connector> NewPipeConLst = Util.GetElementConnectors(newPipe);
NewPipeConLst.First().Radius = narrowCon.Radius;
doc.Regenerate();
//생성된 파이프의 커넥터들 연결
foreach (Connector con in NewPipeConLst)
{
if (con.Origin.IsAlmostEqualTo(narrowCon.Origin, Unit.MMToFeet(0.1)))
con.ConnectTo(narrowCon);
else if (con.Origin.IsAlmostEqualTo(NarrowNextCon.Origin, Unit.MMToFeet(0.1)))
con.ConnectTo(NarrowNextCon);
}
trans.Commit();
}
}
else if (NarrowNextCon.Owner is Pipe)
{
Connector PipeOtherCon = Util.GetOtherConnector(NarrowNextCon);
Connector NextFamilyCon = Util.GetNextElementConnector(PipeOtherCon);
if (NextFamilyCon.Owner is FamilyInstance && NextFamilyCon != null)
{
Line pipeline = (PipeOtherCon.Owner.Location as LocationCurve).Curve as Line;
double pipeDist = pipeline.GetEndPoint(0).DistanceTo(pipeline.GetEndPoint(1));
using (Transaction trans = new Transaction(doc))
{
trans.Start("move");
narrowCon.DisconnectFrom(NarrowNextCon);
//간격 조정 거리보다 레듀셔에 붙은 파이프길이가 클 경우
if (pipeDist > Unit.MMToFeet(Dist))
{
XYZ Vec = (NextFamilyCon.Origin - narrowCon.Origin).Normalize();
//레듀셔 위치조정
MoveElement(doc, narrowCon.Owner,
narrowCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
//파이프 위치조정
MoveElement(doc, NarrowNextCon.Owner,
NarrowNextCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
}
else
{
XYZ Vec = (narrowCon.Origin - NextFamilyCon.Origin).Normalize();
//레듀셔 위치조정
MoveElement(doc, narrowCon.Owner,
narrowCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
//파이프 위치조정
MoveElement(doc, NarrowNextCon.Owner,
NarrowNextCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
}
//커넥터 다시 잇기
narrowCon.ConnectTo(NarrowNextCon);
trans.Commit();
}
}
}
}
else//관경 큰쪽 작업
{
if (WideNextCon.Owner is FamilyInstance)
{
using (Transaction trans = new Transaction(doc))
{
trans.Start("MoveEndCreate");
//레듀셔와 패밀리 커넥터 끊기
WideCon.DisconnectFrom(WideNextCon);
XYZ Vec = (narrowCon.Origin - WideCon.Origin).Normalize();
MoveElement(doc, WideCon.Owner, WideCon.Origin, Vec, Dist);
// trans.Commit();
//}
//MessageBox.Show("1");
//using (Transaction trans = new Transaction(doc))
//{
// trans.Start("CreatePipe");
Pipe newPipe = Pipe.Create(doc, PipeSystemTypeId, PipeTypeId, PipeLevelId, WideCon.Origin, WideNextCon.Origin);
List<Connector> NewPipeConLst = Util.GetElementConnectors(newPipe);
NewPipeConLst.First().Radius = WideCon.Radius;
doc.Regenerate();
//생성된 파이프의 커넥터들 연결
foreach (Connector con in NewPipeConLst)
{
if (con.Origin.IsAlmostEqualTo(WideCon.Origin, Unit.MMToFeet(0.1)))
con.ConnectTo(WideCon);
else if (con.Origin.IsAlmostEqualTo(WideNextCon.Origin, Unit.MMToFeet(0.1)))
con.ConnectTo(WideNextCon);
}
trans.Commit();
}
}
else if (WideNextCon.Owner is Pipe)
{
Connector PipeOtherCon = Util.GetOtherConnector(WideNextCon);
Connector NextFamilyCon = Util.GetNextElementConnector(PipeOtherCon);
if (NextFamilyCon.Owner is FamilyInstance && NextFamilyCon != null)
{
Line pipeline = (PipeOtherCon.Owner.Location as LocationCurve).Curve as Line;
double pipeDist = pipeline.GetEndPoint(0).DistanceTo(pipeline.GetEndPoint(1));
using (Transaction trans = new Transaction(doc))
{
trans.Start("move");
WideCon.DisconnectFrom(WideNextCon);
//간격 조정 거리보다 레듀셔에 붙은 파이프길이가 클 경우
if (pipeDist > Unit.MMToFeet(Dist))
{
XYZ Vec = (NextFamilyCon.Origin - WideCon.Origin).Normalize();
//레듀셔 위치조정
MoveElement(doc, WideCon.Owner,
WideCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
//파이프 위치조정
MoveElement(doc, WideNextCon.Owner,
WideNextCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
}
else
{
XYZ Vec = (WideCon.Origin - NextFamilyCon.Origin).Normalize();
//레듀셔 위치조정
MoveElement(doc, WideCon.Owner,
WideCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
//파이프 위치조정
MoveElement(doc, WideNextCon.Owner,
WideNextCon.Origin, Vec, Math.Abs(Unit.FeetToMM(pipeDist) - Dist));
}
//커넥터 다시 잇기
WideCon.ConnectTo(WideNextCon);
trans.Commit();
}
}
}
}
}
}
catch
{
}
}
//Element 커넥터에 붙어있는 객체를 구하는 함수
public void GetSideElement(Element Elem, ref List<Element> 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, 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(), level.Id, 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, 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, Element elem, XYZ BasePt, XYZ VecPt, double mm_MoveDist)
{
//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);
ElementTransformUtils.MoveElement(doc, elem.Id, NewPt);
}
//패밀리의 타입구분
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;
}
}
}