473 lines
18 KiB
C#
473 lines
18 KiB
C#
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Autodesk.Revit;
|
|
using Autodesk.Revit.DB;
|
|
using Autodesk.Revit.UI;
|
|
using KMBIM.Revit.Tools;
|
|
using Autodesk.Revit.UI.Selection;
|
|
using System.Windows.Forms;
|
|
using Autodesk.Revit.DB.Mechanical;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using KMBIM.Revit.Tools.Utils;
|
|
using Autodesk.Revit.DB.Plumbing;
|
|
using KDCS.Utils;
|
|
using System.IO;
|
|
using KMBIM.Utils;
|
|
|
|
namespace KMBIM.Revit.Tools.Cmd.DuctDraw
|
|
{
|
|
/// <summary>
|
|
/// 덕트 대행자(PlaceHolder:자리 표시자)를 덕트로 변환합니다. 꼬메의 자동작도와 유사한 기능
|
|
/// </summary>
|
|
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
|
|
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
|
|
[Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
|
|
public class DuctDrawCmd : IExternalCommand
|
|
{
|
|
UIApplication m_pUIApp;
|
|
UIDocument uidoc = null;
|
|
Document doc = null;
|
|
|
|
|
|
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet elements)
|
|
{
|
|
try
|
|
{
|
|
if (!WorkMain.GetInstance().IsValid) return Autodesk.Revit.UI.Result.Succeeded;
|
|
m_pUIApp = commandData.Application;
|
|
uidoc = m_pUIApp.ActiveUIDocument;
|
|
doc = uidoc.Document;
|
|
|
|
|
|
|
|
|
|
Selection sel1 = uidoc.Selection;
|
|
|
|
|
|
// 선택한 요소 가져오기
|
|
var ductref = uidoc.Selection.PickObject(ObjectType.Element, "메인 덕트 대행자 선택");
|
|
if (ductref == null) return Result.Failed;
|
|
|
|
|
|
Autodesk.Revit.DB.Mechanical.Duct curSelDuct = doc.GetElement(ductref.ElementId) as Duct;
|
|
if (curSelDuct == null) return Result.Failed;
|
|
|
|
// 선택한 덕트 대행자와 연결된 모든 덕트 대행자 찾기
|
|
var connectedDucts = new List<ElementId>();
|
|
var selectedDucts = new List<ElementId>();
|
|
selectedDucts.Add(curSelDuct.Id);
|
|
|
|
ElementId curId;
|
|
while (selectedDucts.Count > 0)
|
|
{
|
|
curId = selectedDucts.First();
|
|
selectedDucts.RemoveAt(0);
|
|
|
|
|
|
|
|
Element e1 = doc.GetElement(curId);
|
|
Type e1Type = e1.GetType();
|
|
ConnectorManager conMan = null;
|
|
if (e1Type == typeof(Autodesk.Revit.DB.Mechanical.Duct))
|
|
{
|
|
Autodesk.Revit.DB.Mechanical.Duct duct = e1 as Autodesk.Revit.DB.Mechanical.Duct;
|
|
if(duct.IsPlaceholder) connectedDucts.Add(curId);
|
|
conMan = duct.ConnectorManager;
|
|
|
|
}
|
|
else if (e1Type == typeof(FamilyInstance))
|
|
{
|
|
FamilyInstance fi = e1 as FamilyInstance;
|
|
if (fi.MEPModel != null)
|
|
{
|
|
conMan = fi.MEPModel.ConnectorManager;
|
|
}
|
|
|
|
}
|
|
|
|
if (conMan != null)
|
|
{
|
|
foreach (Connector selfcon in conMan.Connectors)
|
|
{
|
|
Connector otherConnector = FindConnectedTo(selfcon);
|
|
if (otherConnector != null)
|
|
{
|
|
if (connectedDucts.Contains(otherConnector.Owner.Id) == false) // 방문 이력이 없는 덕트 아이디만 추가
|
|
{
|
|
selectedDucts.Add(otherConnector.Owner.Id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Duct 타입 가져오기
|
|
DuctType ductType = new FilteredElementCollector(doc)
|
|
.OfClass(typeof(DuctType))
|
|
.Cast<DuctType>()
|
|
.FirstOrDefault(x => x.Name == "Rectangular");
|
|
|
|
|
|
|
|
// 현재 선택한 덕트가 대행자인 경우에만 처리
|
|
if (curSelDuct.IsPlaceholder)
|
|
{
|
|
|
|
|
|
// 대행자를 Duct로 변환
|
|
using (Transaction tx = new Transaction(doc))
|
|
{
|
|
tx.Start("Convert Placeholder to Duct");
|
|
Autodesk.Revit.DB.Mechanical.MechanicalUtils.ConvertDuctPlaceholders(doc, connectedDucts);
|
|
tx.Commit();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
|
|
MechanicalSystemType ductSystemType = null;
|
|
Selection sel1 = uidoc.Selection;
|
|
|
|
DefinitionFile informationFile = OpenSharedParameter();
|
|
|
|
if (null == informationFile)
|
|
{
|
|
return Result.Failed;
|
|
}
|
|
|
|
|
|
XYZ m_pt1 = sel1.PickPoint("시작점 지정");
|
|
|
|
Duct m_duct = null;
|
|
Level viewLevel = Util.GetLevel(doc, doc.ActiveView.Origin.Z, 50.0);
|
|
|
|
ElementId levelId = viewLevel != null ? viewLevel.Id : null;
|
|
|
|
|
|
|
|
|
|
FilteredElementCollector collectorDuct = new FilteredElementCollector(doc);
|
|
var ductSystemTypes = collectorDuct.OfClass(typeof(MechanicalSystemType)).ToElements();
|
|
foreach (MechanicalSystemType systemType in ductSystemTypes)
|
|
{
|
|
if (systemType.SystemClassification == MEPSystemClassification.SupplyAir ||
|
|
systemType.SystemClassification == MEPSystemClassification.ReturnAir)
|
|
{
|
|
ductSystemType = systemType;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ductSystemType == null)
|
|
{
|
|
MessageBox.Show("덕트 시스템유형을 지정할 수 없습니다.");
|
|
return Result.Failed;
|
|
}
|
|
|
|
List<DuctType> ductCollection = new FilteredElementCollector(doc)
|
|
.OfClass(typeof(DuctType))
|
|
.OfType<DuctType>()
|
|
.ToList();
|
|
|
|
|
|
if (ductCollection.Count < 1)
|
|
{
|
|
MessageBox.Show("사용 가능한 덕트 유형이 없습니다.");
|
|
return Result.Failed;
|
|
}
|
|
|
|
|
|
|
|
|
|
DuctType ductType = ductCollection.First();
|
|
|
|
FamilySymbol symbol = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_DetailComponents).OfClass(typeof(FamilySymbol)).Cast<FamilySymbol>().Where(x => x.Name == "kdcs_route").FirstOrDefault();
|
|
FamilyInstanceCreator fiCreator = new FamilyInstanceCreator(m_pUIApp);
|
|
|
|
|
|
XYZ m_pt2 = sel1.PickPoint("다음점 지정");
|
|
|
|
using (Transaction t = new Transaction(doc))
|
|
{
|
|
t.Start("덕트 대행자 생성");
|
|
XYZ vDir = (m_pt2 - m_pt1);
|
|
XYZ vNDir = (m_pt2 - m_pt1).Normalize();
|
|
|
|
XYZ m_ptMid = m_pt1 + vNDir * vDir.GetLength() * 0.5;
|
|
|
|
Duct duct1 = Duct.CreatePlaceholder(doc, ductSystemType.Id, ductType.Id, levelId, m_pt1, m_ptMid);
|
|
// 덕트 사이즈 반영
|
|
duct1.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(Unit.MMToFeet(500));
|
|
duct1.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(Unit.MMToFeet(300));
|
|
// 교차 확인 요소
|
|
KDCSIntersectorElement intersectorElement1 = new KDCSIntersectorElement(duct1);
|
|
Duct duct2 = Duct.CreatePlaceholder(doc, ductSystemType.Id, ductType.Id, levelId, m_ptMid, m_pt2);
|
|
KDCSIntersectorElement intersectorElement2 = new KDCSIntersectorElement(duct2);
|
|
// 덕트 사이즈 반영
|
|
duct2.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(Unit.MMToFeet(300));
|
|
duct2.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(Unit.MMToFeet(250));
|
|
|
|
Connector con1 = intersectorElement1.GetClosestConnector(m_ptMid);
|
|
Connector con2 = intersectorElement2.GetClosestConnector(m_ptMid);
|
|
con1.ConnectTo(con2);
|
|
var fi = doc.Create.NewTransitionFitting(con1, con2);
|
|
t.Commit();
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show(ex.Message);
|
|
return Result.Failed;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Result.Succeeded;
|
|
}
|
|
|
|
|
|
private void InitDuctFlow(Autodesk.Revit.DB.Mechanical.Duct ductMain, DefinitionFile informationFile, string parameterName)
|
|
{
|
|
Definition defIndividualFlow = null;
|
|
Autodesk.Revit.DB.Parameter paramIF = ductMain.LookupParameter(parameterName);
|
|
SharedParameterBindingManager manager = new SharedParameterBindingManager();
|
|
manager.parameterName = parameterName;
|
|
#if _22 || _23
|
|
manager.parameterType = SpecTypeId.AirFlow;
|
|
#else
|
|
manager.parameterType = ParameterType.HVACAirflow;
|
|
#endif
|
|
manager.UserModifiable = true;
|
|
if (paramIF == null)
|
|
{
|
|
DefinitionGroup defGroup = informationFile.Groups.get_Item("Duct");
|
|
if (defGroup != null)
|
|
{
|
|
defIndividualFlow = defGroup.Definitions.get_Item(parameterName);
|
|
if (defIndividualFlow != null)
|
|
{
|
|
// Create a new Binding object with the categories to which the parameter will be bound.
|
|
CategorySet categories = m_pUIApp.Application.Create.NewCategorySet();
|
|
|
|
// get door category and insert into the CategorySet.
|
|
Category ductCategory = m_pUIApp.ActiveUIDocument.Document.Settings.Categories.
|
|
get_Item(BuiltInCategory.OST_PlaceHolderDucts);
|
|
categories.Insert(ductCategory);
|
|
|
|
InstanceBinding instanceBinding = m_pUIApp.Application.Create.NewInstanceBinding(categories);
|
|
BindingMap bindingMap = m_pUIApp.ActiveUIDocument.Document.ParameterBindings;
|
|
|
|
|
|
// for "IndividualFlow"
|
|
if (!AlreadyAddedSharedParameter(m_pUIApp.ActiveUIDocument.Document, parameterName, BuiltInCategory.OST_PlaceHolderDucts))
|
|
{
|
|
Definition instanceIndividualFlow = defGroup.Definitions.get_Item(parameterName);
|
|
|
|
if (null == instanceIndividualFlow)
|
|
{
|
|
#if _23
|
|
ExternalDefinitionCreationOptions ExternalDefinitionCreationOptions2 = new ExternalDefinitionCreationOptions(parameterName, SpecTypeId.AirFlow);
|
|
#else
|
|
ExternalDefinitionCreationOptions ExternalDefinitionCreationOptions2 = new ExternalDefinitionCreationOptions(parameterName, ParameterType.HVACAirflow);
|
|
#endif
|
|
instanceIndividualFlow = defGroup.Definitions.Create(ExternalDefinitionCreationOptions2);
|
|
}
|
|
|
|
using (Transaction trans = new Transaction(doc))
|
|
{
|
|
trans.Start("Add Shared Parameter");
|
|
// Add the binding and definition to the document.
|
|
bindingMap.Insert(instanceIndividualFlow, instanceBinding, BuiltInParameterGroup.PG_MECHANICAL_AIRFLOW);
|
|
trans.Commit();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
private DefinitionFile OpenSharedParameter()
|
|
{
|
|
//Method's return
|
|
DefinitionFile informationFile = null;
|
|
// create shared parameter file
|
|
var location = Util.GetKMBIMLibraryFolder("SharedParameter");
|
|
string sharedParameterFile = Path.Combine(location, "KMBIMSharedParameter.txt");
|
|
if (File.Exists(sharedParameterFile))
|
|
{
|
|
m_pUIApp.Application.SharedParametersFilename = sharedParameterFile;
|
|
informationFile = m_pUIApp.Application.OpenSharedParameterFile();
|
|
}
|
|
|
|
|
|
return informationFile;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Has the specific document shared parameter already been added ago?
|
|
/// </summary>
|
|
/// <param name="doc">Revit project in which the shared parameter will be added.</param>
|
|
/// <param name="paraName">the name of the shared parameter.</param>
|
|
/// <param name="boundCategory">Which category the parameter will bind to</param>
|
|
/// <returns>Returns true if already added ago else returns false.</returns>
|
|
private bool AlreadyAddedSharedParameter(Document doc, string paraName, BuiltInCategory boundCategory)
|
|
{
|
|
try
|
|
{
|
|
BindingMap bindingMap = doc.ParameterBindings;
|
|
DefinitionBindingMapIterator bindingMapIter = bindingMap.ForwardIterator();
|
|
|
|
while (bindingMapIter.MoveNext())
|
|
{
|
|
if (bindingMapIter.Key.Name.Equals(paraName))
|
|
{
|
|
ElementBinding binding = bindingMapIter.Current as ElementBinding;
|
|
CategorySet categories = binding.Categories;
|
|
|
|
foreach (Category category in categories)
|
|
{
|
|
if (category.Id.IntegerValue.Equals((int)boundCategory))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
private Connector FindConnector(Autodesk.Revit.DB.Mechanical.Duct duct, Autodesk.Revit.DB.XYZ conXYZ)
|
|
{
|
|
ConnectorSet conns = duct.ConnectorManager.Connectors;
|
|
foreach (Connector conn in conns)
|
|
{
|
|
if (conn.Origin.IsAlmostEqualTo(conXYZ))
|
|
{
|
|
return conn;
|
|
}
|
|
}
|
|
return null;
|
|
|
|
}
|
|
|
|
private Connector FindConnectedTo(Autodesk.Revit.DB.Mechanical.Duct duct, Autodesk.Revit.DB.XYZ conXYZ)
|
|
{
|
|
Connector connItself = FindConnector(duct, conXYZ);
|
|
ConnectorSet connSet = connItself.AllRefs;
|
|
foreach (Connector conn in connSet)
|
|
{
|
|
if (conn.Owner.Id.IntegerValue != duct.Id.IntegerValue &&
|
|
conn.ConnectorType == ConnectorType.End)
|
|
{
|
|
return conn;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private Connector FindConnectedTo(Connector connItself)
|
|
{
|
|
ConnectorSet connSet = connItself.AllRefs;
|
|
foreach (Connector conn in connSet)
|
|
{
|
|
if (conn.Owner.Id.IntegerValue != connItself.Owner.Id.IntegerValue &&
|
|
conn.ConnectorType == ConnectorType.End)
|
|
{
|
|
return conn;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
private ElementId GetViewLevel(Document doc)
|
|
{
|
|
Autodesk.Revit.DB.View active = doc.ActiveView;
|
|
ElementId levelId = null;
|
|
|
|
Autodesk.Revit.DB.Parameter level = active.LookupParameter("Associated Level");
|
|
|
|
FilteredElementCollector lvlCollector = new FilteredElementCollector(doc);
|
|
ICollection<Element> lvlCollection = lvlCollector.OfClass(typeof(Level)).ToElements();
|
|
|
|
foreach (Element l in lvlCollection)
|
|
{
|
|
Level lvl = l as Level;
|
|
if (lvl.Name == level.AsString())
|
|
{
|
|
levelId = lvl.Id;
|
|
break;
|
|
}
|
|
}
|
|
return levelId;
|
|
}
|
|
|
|
public XYZ getXYZ(UIDocument uidoc, System.Drawing.Point p)
|
|
{
|
|
UIView uiview = GetActiveUiView(uidoc);
|
|
if (uiview == null) return null;
|
|
|
|
Autodesk.Revit.DB.Rectangle rect = uiview.GetWindowRectangle();
|
|
System.Windows.Forms.Cursor.Position = new System.Drawing.Point(p.X, p.Y);
|
|
double dx = (double)(p.X - rect.Left) / (rect.Right - rect.Left);
|
|
double dy = (double)(p.Y - rect.Bottom) / (rect.Top - rect.Bottom);
|
|
IList<XYZ> corners = uiview.GetZoomCorners();
|
|
XYZ a = corners[0];
|
|
XYZ b = corners[1];
|
|
XYZ v = b - a;
|
|
XYZ p3 = a + dx * v.X * XYZ.BasisX + dy * v.Y * XYZ.BasisY;
|
|
|
|
return p3;
|
|
}
|
|
|
|
|
|
public System.Drawing.Point getScreenPoint()
|
|
{
|
|
return System.Windows.Forms.Cursor.Position;
|
|
}
|
|
|
|
private UIView GetActiveUiView(UIDocument uidoc)
|
|
{
|
|
Document doc = uidoc.Document;
|
|
Autodesk.Revit.DB.View view = doc.ActiveView;
|
|
IList<UIView> uiviews = uidoc.GetOpenUIViews();
|
|
UIView uiview = null;
|
|
|
|
foreach (UIView uv in uiviews)
|
|
{
|
|
if (uv.ViewId.Equals(view.Id))
|
|
{
|
|
uiview = uv;
|
|
break;
|
|
}
|
|
}
|
|
return uiview;
|
|
}
|
|
|
|
}
|
|
} |