Client/Desktop/KMBIM3.0/KMBIM3.0_소스/Cmd/SyncPipe/SyncPipe.cs

298 lines
11 KiB
C#

using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using System.Threading.Tasks;
using KDCS.Utils;
using System.Collections;
using System.Windows.Forms;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.DB.Mechanical;
using System.Xml.Linq;
using Autodesk.Revit.UI.Events;
using System.IO;
using KMBIM.Revit.Tools;
using KMBIM.Revit.Tools.Cmd.SyncPipe;
/// <summary>
/// 단열재를 선택적으로 고려하며 기준 배관의 간격 띄우기 값을 기준으로 나머지 선택한 배관(들)의 높이를 통일 시킨다.
/// Sync pipe's offset with criteria pipe that user selected.
/// Made By 이주호(Lee Juho), DCS Company, South Korea
/// 2021.07.09 ~ 2021.07.13
/// </summary>
namespace KMBIM
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
/*
1. 간격띄우기 값 바꿀 배관(들) 선택
2. 기준 배관 선택
3. winForm 띄워서 기준점 선택
4. 선택 받은 기준점을 토대로 연산해서 배관 간격띄우기 값 편집
*/
public class SyncPipe : IExternalCommand
{
UIApplication uiapp;
UIDocument uidoc;
Autodesk.Revit.DB.Document doc = null;
Autodesk.Revit.ApplicationServices.Application app = null;
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
try
{
//if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded;
// Verify active document
if (null == commandData.Application.ActiveUIDocument.Document)
{
message = "현재 활성화된 뷰가 없습니다.";
return Result.Failed;
}
uiapp = commandData.Application;
uidoc = uiapp.ActiveUIDocument;
app = uiapp.Application;
doc = uidoc.Document;
List<Pipe> pList = new List<Pipe>();
IList<Reference> rList = uidoc.Selection.PickObjects(ObjectType.Element, new PipeSelectionFilter(), "위치 바꿀 배관 선택: ");
foreach(Reference r in rList)
{
if (r == null) return Result.Cancelled;
Pipe movePipe = doc.GetElement(r.ElementId) as Pipe;
pList.Add(movePipe);
}
//위치 바꿀 배관 간격 띄우기, 외경 파라미터 구하기
List<Parameter> movePipeParamList = new List<Parameter>();
List<double> movePipeOffsetParamList = new List<double>();
List<double> movePipeOuterDiaParamList = new List<double>();
List<double> movePipeInsultionParamList = new List<double>();
List<mvPipeData> mpdList = new List<mvPipeData>();
foreach (Pipe p in pList)
{
if (p == null)//선택한 것이 파이프가 아니면 패스
{
continue;
}
Parameter mvPipeOffsetParam = p.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM);//간격 띄우기
double mvPipeOffset = mvPipeOffsetParam.AsDouble();
Parameter mvPipeODiaParam = p.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER);//외경
double mvPipeODia = mvPipeODiaParam.AsDouble();
Parameter mvPipeInsulTickParam = p.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS);//단열재 두께
double mvPipeInsulTick = mvPipeInsulTickParam.AsDouble();
movePipeParamList.Add(mvPipeOffsetParam);
movePipeOffsetParamList.Add(mvPipeOffset);
movePipeOuterDiaParamList.Add(mvPipeODia);
//클래스를 사용해서 한 세트로
mvPipeData mpd = new mvPipeData();
mpd.Id = p.Id;
mpd.Od = mvPipeODia;
mpd.InsultionTick = mvPipeInsulTick;
mpd.Param = mvPipeOffsetParam;
//배열로 쌓기
mpdList.Add(mpd);
}
//기준 배관에서 필요한 데이터 추출---------------------------------------------------------------------------------------------------------
Reference refer = uidoc.Selection.PickObject(ObjectType.Element, new PipeSelectionFilter(), "기준 배관 선택: ");
Pipe criteriaPipe = doc.GetElement(refer.ElementId) as Pipe;
if (criteriaPipe == null)
{
MessageBox.Show("기준은 배관이여야 합니다.", "오류");
return Result.Failed;
}
Autodesk.Revit.DB.Parameter criteriaPipeOffestParam = criteriaPipe.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM);
double criteriaPipeOffset = criteriaPipeOffestParam.AsDouble();
Autodesk.Revit.DB.Parameter criteriaOuterDiaParam = criteriaPipe.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER);
double criteriaOuterDia = criteriaOuterDiaParam.AsDouble();
Parameter insulationParam = criteriaPipe.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS);
double criteriaInsultion = insulationParam.AsDouble();
//------------------------------------------------------------------------------------------------------------------------------------
SelectLocation sl = new SelectLocation();
sl.ShowDialog();
if(sl.ccValue == 1)//윈폼에서 Cancel 누른 경우 명령 취소
{
return Result.Cancelled;
}
//유저가 winForm에서 선택한 원하는 위치값 구하기
double newPipeOffset = GetLocationByUserInput(sl.insulValue, sl.value, criteriaPipeOffset, criteriaOuterDia, criteriaInsultion);
using (Transaction tr = new Transaction(doc))
{
tr.Start("start");
double mvPipeLoc = 0;
//선택한 배관(들)의 배치점 구하기.(위에서 구한 위치값으로 간격띄우기값을 조정하면 기준 선에 배관이 정렬되지 않기 때문)
foreach (var a in mpdList)
{
//단열재 등의 고려사항을 다 연산해서 배치점 구하기
mvPipeLoc = GetMovePipeLocation(sl.insulValue, sl.value, a.InsultionTick, newPipeOffset, a.Od);
a.Param.Set(mvPipeLoc);
}
tr.Commit();
}
}
catch (Exception e)
{
//MessageBox.Show(e.Message);
}
return Result.Succeeded;
}
//기준 Offset구하기
public double GetLocationByUserInput(int insultion, int value, double criteriaPipeOffset, double criteriaOuterDia, double insultionTick)
{
double newPipeOffset = 0;
switch (insultion)
{
case (1)://단열재 고려 X
switch (value)
{
case (1):
newPipeOffset = criteriaPipeOffset + (criteriaOuterDia / 2);//상부 일치
break;
case (2):
newPipeOffset = criteriaPipeOffset;//중간 일치
break;
case (3):
newPipeOffset = criteriaPipeOffset - (criteriaOuterDia / 2);//하부 일치
break;
}
break;
case (2)://단열재 고려 O
switch (value)
{
case (1):
newPipeOffset = criteriaPipeOffset + ((criteriaOuterDia / 2) + insultionTick);
break;
case (2):
newPipeOffset = criteriaPipeOffset + insultionTick;
break;
case (3):
newPipeOffset = criteriaPipeOffset - ((criteriaOuterDia / 2) + insultionTick);
break;
}
break;
}
return newPipeOffset;
}
/// <summary>
/// 값 계산해서 이동할 배관들 배치점 찾기
/// </summary>
/// <param name="insulValue">wimForm에서 선택한 단열재 고려 여부</param>
/// <param name="value">winForm에서 선택한 기준 배치점 위치(상중하)</param>
/// <param name="insultionTick">단열재 두께</param>
/// <param name="newPipeOffset">기준 배치점</param>
/// <param name="od">내경</param>
/// <returns></returns>
public double GetMovePipeLocation(int insulValue, int value, double insultionTick, double newPipeOffset, double od)
{
double mvPipeLoc = 0;
switch (insulValue)
{
case (1)://단열제 미고려
switch (value)
{
case (1):
mvPipeLoc = newPipeOffset - (od / 2 );//상부
break;
case (2):
mvPipeLoc = newPipeOffset;//중간
break;
case (3):
mvPipeLoc = newPipeOffset + (od / 2);//하부
break;
}
break;
case (2)://단열재 고려
switch (value)
{
case (1):
mvPipeLoc = newPipeOffset - (od / 2 + insultionTick);//상부
break;
case (2):
mvPipeLoc = newPipeOffset;//중간
break;
case (3):
mvPipeLoc = newPipeOffset + (od / 2 + insultionTick);//하부
break;
}
break;
}
return mvPipeLoc;
}
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;
}
}
}
public class mvPipeData
{
public ElementId Id { get; set; }
public double Od { get; set; }
public double InsultionTick { get; set; }
public Parameter Param { get; set; }
}
}