Client/Desktop/KMBIM3.0/23.10.16/Cmd/Sprinkler/SprinKlerSort.cs

262 lines
10 KiB
C#

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using System.Collections.Generic;
using System.Linq;
//using COME4Revit.WinForm;
using System.Diagnostics;
using Autodesk.Revit.UI.Selection;
using System;
using System.Windows.Forms;
using KDCS.Utils;
using View = Autodesk.Revit.DB.View;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.Creation;
namespace KMBIM
{
class SpkrInfor
{
public ElementId m_SpID; //헤드 ID
public Connector HeadCon = null;
public XYZ m_Headpt = null; //헤드 커넥터 점.
public XYZ m_InterPt = null; //헤드와 메인관 수직점
public double m_Ep2InterDst = 0; // 메인 끝점과 수직점 사이 거리
public bool EqVector = true;//현재 백터와 이전 벡터가 같은지(다르면 90도 꺾인 작도 위해)
public XYZ SeparateionPt = null; // 하향식 - 이격거리 점
}
class SpkrComparer : IComparer<SpkrInfor>
{
public int Compare(SpkrInfor a, SpkrInfor b)
{
double diff = a.m_Ep2InterDst - b.m_Ep2InterDst;
if (Math.Abs(diff) < 0.0001) return 0;
else if (diff > 0.0001) return 1;
else if (diff < 0.0001) return -1;
else return 0;
}
}
class SpkrOrthoComparer : IComparer<SpkrInfor>
{
public int Compare(SpkrInfor a, SpkrInfor b)
{
double diff = a.m_Headpt.DistanceTo(b.m_InterPt) - b.m_Headpt.DistanceTo(a.m_InterPt);
if (Math.Abs(diff) < 0.0001) return 0;
else if (diff > 0.0001) return 1;
else if (diff < 0.0001) return -1;
else return 0;
}
}
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class SprinKlerSort : IExternalCommand
{
UIApplication uiapp;
UIDocument uidoc;
Autodesk.Revit.DB.Document doc;
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
uiapp = commandData.Application;
uidoc = uiapp.ActiveUIDocument;
Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
doc = uidoc.Document;
try
{
//기준 파이프 선택
Reference pipeRef = commandData.Application.ActiveUIDocument.Selection.PickObject(ObjectType.Element, new PipeSelectionFilter(), "기준 배관 선택 : ");
//기준 스프링클러 선택
IList<Reference> spkrRefs = commandData.Application.ActiveUIDocument.Selection.PickObjects(ObjectType.Element, new SpkrSelectionFilter(), "정렬할 스프링클러 범위 지정 : ");
Element pipeElem = doc.GetElement(pipeRef);
List<Element> spkrElemLst = new List<Element>();
foreach (Reference refer in spkrRefs)
{
spkrElemLst.Add(doc.GetElement(refer));
}
//기준 파이프 라인
Line pipeLine = ((pipeElem as Pipe).Location as LocationCurve).Curve as Line;
if (pipeLine == null) return Result.Cancelled;
SpkrInfor Infor = new SpkrInfor();
List<SpkrInfor> inforLst = new List<SpkrInfor>();
XYZ ep2interVec = null;
foreach (Element elem in spkrElemLst)
{
FamilyInstance family = elem as FamilyInstance;
List<Connector> conLst = Util.GetElementConnectors(family);
foreach (Connector con in conLst)
{
IntersectionResult interRes = pipeLine.Project(con.Origin);
XYZ interpt = new XYZ(interRes.XYZPoint.X, interRes.XYZPoint.Y, con.Origin.Z);
SpkrInfor infor = new SpkrInfor();
infor.HeadCon = con;
infor.m_Headpt = con.Origin;
infor.m_InterPt = interpt;
infor.m_SpID = con.Owner.Id;
//Util.Pyosi(doc, interRes.XYZPoint, 1);
infor.m_Ep2InterDst = interRes.XYZPoint.DistanceTo(pipeLine.GetEndPoint(1));
ep2interVec = (interRes.XYZPoint - pipeLine.GetEndPoint(1)).Normalize();
inforLst.Add(infor);
}
}//foreach end
SpkrComparer SC = new SpkrComparer();
SpkrOrthoComparer SOC = new SpkrOrthoComparer();
inforLst.Sort(SC);
List<List<SpkrInfor>> m_TotalLst = new List<List<SpkrInfor>>();
while (true)
{
if (inforLst.Count <= 0) break;
List<SpkrInfor> Group = DivideObjSprinKlerData(pipeElem as Pipe, inforLst);
foreach (SpkrInfor infor in Group)
{
inforLst.Remove(infor);
}
//나눈 그룹 리스트에 담기.
if (Group.Count > 0)
m_TotalLst.Add(Group);
}//while end
foreach (List<SpkrInfor> spkrLst in m_TotalLst)
{
if (spkrLst.Count <= 0) continue;
double total_InterDst = 0;
double avgDst = 0;
foreach (SpkrInfor spkr in spkrLst)
{
total_InterDst += spkr.m_Ep2InterDst;
}
//그룹 스프링클러들의 평균거리 구함
if (total_InterDst != 0)
{
avgDst = total_InterDst / spkrLst.Count;
XYZ AvgPt = Util.Polar(pipeLine.GetEndPoint(1), (spkrLst.First().m_InterPt - pipeLine.GetEndPoint(1)).Normalize(), avgDst);
}
//ElementTransformUtils.MoveElement 함수 사용 시 스프링클러가 사라짐.
using (Transaction trans = new Transaction(doc))
{
trans.Start("moveSpkr");
foreach (SpkrInfor spkr in spkrLst)
{
XYZ movePt = Util.Polar(spkr.m_Headpt, ep2interVec, avgDst - spkr.m_Ep2InterDst);
FamilyInstance family = doc.GetElement(spkr.m_SpID) as FamilyInstance;
LocationPoint locpt = family.Location as LocationPoint;
locpt.Point = movePt;
}
trans.Commit();
}
}
}
catch(Exception)
{
//MessageBox.Show("" + e);
}
return Result.Succeeded;
}
List<SpkrInfor> DivideObjSprinKlerData(Pipe mainPipe, List<SpkrInfor> MainObjLst)
{
List<SpkrInfor> resLst = new List<SpkrInfor>();
resLst.AddRange(MainObjLst);
SpkrInfor obj1st = MainObjLst.First();
foreach (SpkrInfor obj in MainObjLst)
{
double aa = Math.Round(Unit.FeetToMM(obj1st.m_InterPt.DistanceTo(obj.m_InterPt)), 3);
if (Math.Round(Unit.FeetToMM(obj1st.m_InterPt.DistanceTo(obj.m_InterPt)), 3) >= 1000)
{
int ctIdx = resLst.IndexOf(obj);
resLst.RemoveAt(ctIdx);
}
}
XYZ sp = null, ep = null;
Util.GetStartEndPoint(mainPipe, ref sp, ref ep);
for (int i = 0; i < resLst.Count(); i++)
{
for (int k = 0; k < resLst.Count(); k++)
{
if (i == k) continue;
SpkrInfor obj_i = resLst[i];
SpkrInfor obj_k = resLst[k];
bool i_right = Util.isRightPoint(obj_i.m_Headpt, sp, ep);
bool k_right = Util.isRightPoint(obj_k.m_Headpt, sp, ep);
//메인관 기준 같은 쪽 헤더가 아니면 넘어감
if (i_right != k_right) continue;
double i_inter2HeadDst = obj_i.m_InterPt.DistanceTo(obj_i.m_Headpt);
double k_inter2HeadDst = obj_k.m_InterPt.DistanceTo(obj_k.m_Headpt);
//헤드점-메인관교차점 길이가 같은게 그룹에 있을 경우 (● ●)
if (Math.Abs(i_inter2HeadDst - k_inter2HeadDst) < Unit.MMToFeet(0.01))
{
resLst.Remove(obj_k);
break;
}
}
}
return resLst;
}
public class SpkrSelectionFilter : ISelectionFilter
{
public bool AllowElement(Element element)
{
if (element.Category == null) return false;
if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Sprinklers)
{
return true;
}
return false;
}
public bool AllowReference(Reference refer, XYZ point)
{
return false;
}
}
public class PipeSelectionFilter : ISelectionFilter
{
public bool AllowElement(Element element)
{
if (element.Category == null) return false;
if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves)
{
return true;
}
return false;
}
public bool AllowReference(Reference refer, XYZ point)
{
return false;
}
}
}
}