[ 목표 ]

Revit api 를 활요하여 Duct 를 생성하고 Elbow를 이용하여 Duct Fitting 처리한다.

 

[ 방법 ] 

 

1) UIdocument 에서 선택한 modelLine을 가져온다.
2) line에 맞춰 Duct 생성한다. 
3) 생성된 Duct 끼리 elbow로 Fitting 시킨다.
4) line 삭제한다.

 

 public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            App.m_App = commandData.Application;
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
            Document document = uidoc.Document;

            // 선택한 Line 가져오기
            List<Element> elementList = GetDuctLine(uidoc, document);
            CreateDuct(uidoc, document, elementList);

            return Result.Succeeded;
        }

 

//선택한 개체를 필터링할 수 있는 인터페이스 구현(= An interface that provides the ability to filter objects during a selection operation)
        public class PlanarFacesSelectionFilter : ISelectionFilter
        {
            Document doc = null;
            public PlanarFacesSelectionFilter(Document document)
            {
                doc = document;
            }

            public bool AllowElement(Element elem)
            {
                return true;
            }

            public bool AllowReference(Reference reference, XYZ position)
            {
                if (doc.GetElement(reference).GetGeometryObjectFromReference(reference) is PlanarFace)
                { return true; }
                return false;
            }
        }

 

 public List<Element> GetDuctLine(UIDocument uidoc, Document document)
        {
            ISelectionFilter selectionFilter = new PlanarFacesSelectionFilter(document);
            IList<Reference> references = uidoc.Selection.PickObjects(ObjectType.Element, selectionFilter, "Select Multiple planar faces");
            List<Element> elementList = new List<Element>();

            foreach (Reference reference in references)
            {
                Element element = uidoc.Document.GetElement(reference);
                elementList.Add(element);
            }

            return elementList;
        }

 

 public void CreateDuct(UIDocument uidoc, Document document, List<Element> elementList)
        {
            // (1) Duct 생성하기

            // 1-1) Duct 생성에 필요한 속성 임의로 가져오기

            DuctType ductType = new FilteredElementCollector(document).OfClass(typeof(DuctType)).Cast<DuctType>().Where(a => a.FamilyName.Contains("Oval")).FirstOrDefault();
            Level level = new FilteredElementCollector(document).OfClass(typeof(Level)).First() as Level;
            List<ElementId> DuctSystemTypelst = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_DuctSystem).ToElementIds().ToList();
            ElementId systemTypeId = DuctSystemTypelst.FirstOrDefault();

            // 1-2) 변수선언

            Duct newduct = null;
            XYZ start = null;
            XYZ end = null;

            // 1-3) geometryElements 생성하기

            List<GeometryElement> geometryElements = new List<GeometryElement>();

            foreach (Element element in elementList)
            {
                GeometryElement geometry = element.get_Geometry(new Options());
                geometryElements.Add(geometry);
            }

            // 1-4) Transaction 시작

            Transaction trans = new Transaction(document);
            trans.Start("Create Duct");

            // 1-5) Duct 생성 후 리스트 담기

            List<Line> lines = new List<Line>();
            List<Duct> ducts = new List<Duct>();
            List<Element> eleDuct = new List<Element>();
            foreach (GeometryElement geometry in geometryElements)
            {
                foreach (GeometryObject geometryObject in geometry)
                {
                    Line line = geometryObject as Line;
                    lines.Add(line);

                    start = line.GetEndPoint(0);
                    end = line.GetEndPoint(1);

                    newduct = Duct.Create(document, systemTypeId, ductType.Id, level.Id, start, end);
                    ducts.Add(newduct);
                    Element element = document.GetElement(newduct.Id as ElementId);
                    eleDuct.Add(element);

                    // 1-6) fitting 할 elbow 굵기에 맞게 duct 굴기 설정하기

                    Parameter width = element.LookupParameter("Width");
                    width.Set(10 * 0.09);
                    Parameter height = element.LookupParameter("Height");
                    height.Set(10 * 0.09);

                }
            }

            // 1-6) transaction 안에서 duct fitting종류 설정했으므로 중간에 새로고침하여 값 적용되도록 하기

            document.Regenerate();

            // (2) Duct 연결시키기 ( NewElbowFitting 메소드 사용)
                // 2-1) Duct 연결할 elbow Type 지정하기
                ElementType elementType = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_DuctFitting).OfClass(typeof(ElementType)).Cast<ElementType>().Where(x => x.FamilyName.Equals("M_Oval Elbow - Gored")).FirstOrDefault();
                RoutingPreferenceManager rpm = newduct.DuctType.RoutingPreferenceManager;
                rpm.AddRule(RoutingPreferenceRuleGroupType.Elbows, new RoutingPreferenceRule(elementType.Id, "Duct Fitting"));
                int routingPerenceGroupCnt = rpm.GetNumberOfRules(RoutingPreferenceRuleGroupType.Elbows);
                if (routingPerenceGroupCnt > 1)
                {
                    for (int k = 0; k < routingPerenceGroupCnt - 1; k++)
                    {
                        rpm.RemoveRule(RoutingPreferenceRuleGroupType.Elbows, 0);
                    }
                }

                // 2-2) 연결시킬 덕트 connector 가져오기위해 connectmanager로 connectors 뽑아내기
                for (int i = 0; i < ducts.Count() - 1; i++)
                {
                    ConnectorManager duct_connectorManager1 = ducts[i].ConnectorManager;
                    ConnectorSet duct_connectorSet1 = duct_connectorManager1.Connectors;
                    ConnectorManager duct_connectorManager2 = ducts[i + 1].ConnectorManager;
                    ConnectorSet duct_connectorSet2 = duct_connectorManager2.Connectors;

                    // 2-3) duct 가 가지고 있는 connector 중에서 가장 가까운 connector 뽑아내기
                    Connector connector1 = null;
                    Connector connector2 = null;
                    double minDist = double.MaxValue;

                    foreach (Connector conn1 in duct_connectorSet1)
                    {
                        foreach (Connector conn2 in duct_connectorSet2)
                        {
                            double distance = conn1.Origin.DistanceTo(conn2.Origin);
                            if (distance < minDist)
                            {
                                connector1 = conn1;
                                connector2 = conn2;
                                minDist = distance;
                            }
                        }
                    }
                    try
                    {
                        document.Create.NewElbowFitting(connector1, connector2);
                    }
                    catch (Exception ex)
                    {
                        TaskDialog.Show("오류창", "Duct fitting 에 실패했습니다.\n파이프간의 각도가 너무 크거나 작지 않은지 확인해 주세요\n\n [ 자세한 오류 메세지 ] \n " + ex.Message);
                        trans.RollBack();
                    }
                }

                // (3) duct 와 겹치는 line 삭제하기
                foreach (Element element in elementList)
                {
                    ElementId elementId = element.Id;
                    document.Delete(elementId);
                }
                trans.Commit();
        }

 

 [ 주의할점 ]

 

Revit api 를 활용하여 Duct Fitting을 할 경우 Duct 끼리 이어질 Elbow 의 기본값이 None 으로 지정된다.

따라서, Duct 생성후 Routing Preferences 에서 어떤 Elbow와 Fitting시킬 것인지 RoutingPreferenceManager api 를 이용하여 elbowType 을 지정해준다.

 

반응형

+ Recent posts