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 { /// /// 덕트 대행자(PlaceHolder:자리 표시자)를 덕트로 변환합니다. 꼬메의 자동작도와 유사한 기능 /// [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(); var selectedDucts = new List(); 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() .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 ductCollection = new FilteredElementCollector(doc) .OfClass(typeof(DuctType)) .OfType() .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().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; } /// /// Has the specific document shared parameter already been added ago? /// /// Revit project in which the shared parameter will be added. /// the name of the shared parameter. /// Which category the parameter will bind to /// Returns true if already added ago else returns false. 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 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 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 uiviews = uidoc.GetOpenUIViews(); UIView uiview = null; foreach (UIView uv in uiviews) { if (uv.ViewId.Equals(view.Id)) { uiview = uv; break; } } return uiview; } } }