Client/Desktop/KMBIM3.0/23.10.18/Cmd/TrimSpacing/PipeTrimSpacing - 기준파이프시작점기...

324 lines
14 KiB
C#

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<Element> m_ElemLst = new List<Element>();
try
{
//commandData.Application.ActiveUIDocument.Selection.PickBox(PickBoxStyle.Crossing)
//List<Element> 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<Reference> 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<XYZ> m_DivPtLst = new List<XYZ>();
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;
}
/// <summary>
/// 유니온 피팅
/// </summary>
/// <param name="elem"></param> 파이프
/// <param name="divPt"></param> 자를 점 위치
/// <param name="TrimDist"></param> 1본 길이
/// <param name="NotDrawCnt"></param> 유니온 피팅 실패 갯수
/// <returns></returns>
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)<mainspCon.Radius*3
|| divPt.DistanceTo(mainepCon.Origin) < mainspCon.Radius * 3)
{
return null;
}
//파이프 자르기
List<ElementId> ElemIDLst = Util.DivideElement(doc, mainPipe, divPt);
if (ElemIDLst != null)
{
//List<Connector> famconlst = Util.GetElementConnectors(newFamily);
List<Connector> pipe1conlst = Util.GetElementConnectors(doc.GetElement(ElemIDLst.First()));
List<Connector> 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<Connector> 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;
}
}
}
}