[ 목표 ]

Revit api 를 활용하여 line 선택시 자동으로 Duct Cross Fitting 하기

 

[ 방법 ]

1) UIdocument 에서 선택한 modelLine을 가져온다.

2) line에 맞춰 Duct 생성한다.

3) Duct 끼리 Intersect 되는 부분이 connector와 일치할 경우

- 원하는 elbowfitting시킨다.

- Newelbowfitting 메소드 사용

3) Duct 끼리 Intersect 되는 부분이 connector와 일치하지 않을 경우

교차점을 기준으로 파이프 자른다.

- intersecNewCrossFitting 메소드 이용한다.

원하는 crosses 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);
            List<Element> elementList = new List<Element>();
            if (MessageBox.Show("Duct 생성하시려면 line 을 선택 후 \n좌측 하단의 Finsh 버튼을 클릭해주세요", "Duct 생성확인", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                IList<Reference> references = uidoc.Selection.PickObjects(ObjectType.Element, selectionFilter, "Select Multiple planar faces");
                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;
            XYZ splitpoint = null;
            // 1-3) geometryElements 생성하기

            List<Line> lines = new List<Line>();
            foreach (Element element in elementList)
            {
                GeometryElement geometry = element.get_Geometry(new Options());
                foreach (GeometryObject geometryObject in geometry)
                {
                    Line line = geometryObject as Line;
                    lines.Add(line);
                }

            }

            // 1-4) Transaction 시작

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

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

            List<Duct> ducts = new List<Duct>();
            List<Element> eleDuct = new List<Element>();

            foreach (Line line in lines)
            {
                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.2);
                Parameter height = element.LookupParameter("Height");
                height.Set(10 * 0.2);
            }

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

            // (2) Duct 연결시키기 ( NewElbowFitting 메소드 사용)
            for (int i = 0; i < ducts.Count(); i++)
            {

                // 교차점이 있는지 확인하기
                int num = 0;
                List<int> numlist = new List<int>();
                IntersectionResultArray result = null;
                List<IntersectionResultArray> results = new List<IntersectionResultArray>();

                for (int j = i + 1; j < lines.Count; j++)
                {
                    Line line1 = lines[i];
                    Line line2 = lines[j];

                    line1.Intersect(line2, out result);
                    if (result != null)
                    {
                        results.Add(result);
                        num = j;
                        numlist.Add(num);
                        result = null;
                    }
                }

                if (results != null)
                {
                    for (int k = 0; k < results.Count; k++)
                    {
                        IntersectionResult iResult = results[k].get_Item(0);
                        XYZ IntersectPoint = iResult.XYZPoint;

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

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

                        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;
                                }
                            }
                        }

                        // 2-4) crossfitting 여부확인을 위해, 교차점이 있는지 & 교차점이 connector 와 일치하는지 확인
                        if (connector1.Origin.DistanceTo(IntersectPoint) > 0.001)
                        {
                            iscross = true;
                        }

                        // (3) 파이프끼리 크로스되지 않고 연결되있을때
                        if (iscross == false)
                        {
                            try
                            {
                                // 3-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 t = 0; t < routingPerenceGroupCnt - 1; t++)
                                    {
                                        rpm.RemoveRule(RoutingPreferenceRuleGroupType.Elbows, 0);
                                    }
                                }

                                document.Create.NewElbowFitting(connector1, connector2);
                            }
                            catch (Exception ex)
                            {
                                if (ex.Message.Contains("them is too small or too large"))
                                {
                                    TaskDialog.Show("오류창", "Duct 간의 각도가 너무 크거나 작습니다.\n조정후다시 시도해주세요");
                                }
                                else
                                {
                                    TaskDialog.Show("오류창", "Duct fitting 에 실패했습니다.\n\n [ 자세한 오류 메세지 ] \n " + ex.Message);
                                }
                               
                            }
                        }

                        // (3)파이프끼리 크로스되어 있을때
                        else
                        {
                            // 3-1) 파이프 자르기
                            ElementId newDuctId1 = Autodesk.Revit.DB.Mechanical.MechanicalUtils.BreakCurve(document, ducts[i].Id, IntersectPoint);
                            ElementId newDuctId2 = Autodesk.Revit.DB.Mechanical.MechanicalUtils.BreakCurve(document, ducts[numlist[k]].Id, IntersectPoint);
                            Duct splitduct1 = document.GetElement(newDuctId1) as Duct;
                            Duct splitduct2 = document.GetElement(newDuctId2) as Duct;

                            document.Regenerate();
                            // 3-2) 연결시킬 덕트 connector 가져오기위해 connectmanager로 connectors 뽑아내기

                            ConnectorManager duct_connectorManager3 = splitduct1.ConnectorManager;
                            ConnectorSet duct_connectorSet3 = duct_connectorManager3.Connectors;
                            ConnectorManager duct_connectorManager4 = splitduct2.ConnectorManager;
                            ConnectorSet duct_connectorSet4 = duct_connectorManager4.Connectors;

                            //// 3-3) duct 가 가지고 있는 connector 중에서 가장 가까운 connector 뽑아내기
                            Connector connector3 = null;
                            Connector connector4 = null;

                            double minDist2 = double.MaxValue;
                            foreach (Connector conn3 in duct_connectorSet3)
                            {
                                foreach (Connector conn4 in duct_connectorSet4)
                                {
                                    double distance2 = conn3.Origin.DistanceTo(conn4.Origin);
                                    if (distance2 < minDist2)
                                    {
                                        connector3 = conn3;
                                        connector4 = conn4;
                                        minDist2 = distance2;
                                    }
                                }
                            }
                            // 3-4) duct 연결시키기
                            try
                            {
                                // 3-5) Duct 연결할 elbow Type 지정하기
                                ElementType elementType = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_DuctFitting).OfClass(typeof(ElementType)).Cast<ElementType>().Where(x => x.FamilyName.Equals("M_Oval Cross - Straight")).FirstOrDefault();
                                RoutingPreferenceManager rpm = newduct.DuctType.RoutingPreferenceManager;
                                rpm.AddRule(RoutingPreferenceRuleGroupType.Crosses, new RoutingPreferenceRule(elementType.Id, "Duct Fitting"));
                                int routingPerenceGroupCnt = rpm.GetNumberOfRules(RoutingPreferenceRuleGroupType.Crosses);
                                if (routingPerenceGroupCnt > 1)
                                {
                                    for (int t = 0; t < routingPerenceGroupCnt - 1; t++)
                                    {
                                        rpm.RemoveRule(RoutingPreferenceRuleGroupType.Crosses, 0);
                                    }
                                }
                                
                                document.Create.NewCrossFitting(connector1, connector3, connector2, connector4);                               
                            }
                            catch (Exception ex)
                            {
                                if (ex.Message.Contains("them is too small or too large"))
                                {
                                    TaskDialog.Show("오류창", "Duct 간의 각도가 너무 크거나 작습니다.\n조정후다시 시도해주세요");
                                }
                                else
                                {
                                    TaskDialog.Show("오류창", "Duct fitting 에 실패했습니다.\n\n [ 자세한 오류 메세지 ] \n " + ex.Message);
                                }
                            }
                        }
                    }
                }
            }
            //// (4) duct 와 겹치는 line 삭제하기
            foreach (Element element in elementList)
            {
                ElementId elementId = element.Id;
                document.Delete(elementId);
            }
            trans.Commit();
        }

 

 

[ 주의할점 ]

1. Line 그리는 순서에 상관없이 fitting이 될 수 있도록 logic 구성해야한다.

2. Elbow fitting을 할지 creoss fitting을 할지는 connector와 일치하는지 방법 등등으로 확인하여 진행한다.

반응형

[ 목표 ]

Revit api 를 활용하여 line 선택시 교차점을 중심으로 line split 한 뒤 Duct 생성하기

 

[ 방법 ]

1)    Line 가져오기

2)    교차점을 중심으로 line 자르기

3)    Line 잘라졌는지 확인하기 위해 Detail Line 그리기 ( 선택사항 )

4)    파이프 생성

 

            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);
                } 
                                             
            // 1-3) geometryElements 생성하기

            List<Line> lines = new List<Line>();
            foreach (Element element in elementList)
            {
                GeometryElement geometry = element.get_Geometry(new Options());
                foreach (GeometryObject geometryObject in geometry)
                {
                    Line line = geometryObject as Line;
                    lines.Add(line);
                }
            }

           // 교차점이 있는지 확인하기
            IntersectionResultArray results = null;
            Line line1 = lines[0];
            Line line2 = lines[1];
            line1.Intersect(line2, out results);
            IntersectionResult iResult = results.get_Item(0);
            var IntersectPoint = iResult.XYZPoint;

            if (IntersectPoint != null)
            {
                List<Line> splitLines = new List<Line>();
                DetailLine detailLine1 = null;
                DetailLine detailLine2 = null;
                // 교차점 기준으로 라인 자르기
                for (int i = 0; i < lines.Count; i++)
                {
                    Curve curve = lines[i];

                    double paraIntersection = curve.Project(IntersectPoint).Parameter;
                    double startpam = curve.GetEndParameter(0);
                    double endpam = curve.GetEndParameter(1);
                    Curve curve1 = curve.Clone();
                    Curve curve2 = curve.Clone();
                    curve1.MakeBound(startpam, paraIntersection);
                    curve2.MakeBound(paraIntersection, endpam);

                    splitLines.Add(curve1 as Line);
                    splitLines.Add(curve2 as Line);


                    // 평면도에서 교차점 기준으로 잘라낸 선분이 보일 수 있도록 DETAILLINE 생성하기 
                    detailLine1 = document.Create.NewDetailCurve(document.ActiveView, curve1) as DetailLine;
                    detailLine2 = document.Create.NewDetailCurve(document.ActiveView, curve2) as DetailLine;
                }

                lines.Clear();
                lines = splitLines;

            }

 

line split 전

 

line split 후

 

 

[ 주의할점 ]

1.     2개의 line 에 교차점이 존재할 경우, 교차점을 기준으로 Curve Class MakeBound를 이용하여 라인을 자른다. 이때, document 상에서는 4등분 된 line 이 보이지 않는다. 만약 document 상에서 split line을 확인하고 싶다면 detailline 혹은 modelline을 생성하여 제대로 잘라졌는지 확인하면된다.

2.     Datailline 을 그린 후 selection 할 시 3D 뷰에서는 선택되지 않는다. 따라서, level1과 같은 평면도에서 detail line을 선택해야한다.

반응형

[ 목표 ]

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 을 지정해준다.

 

반응형

오류원인: 

 

ElbowFitting 할때 , Routing Preference의 Elbow 종류가 설정되어 있지 않다.

 

해결방법 : 

 

Element 의 Type Edit > Routing Preferences Edit 클릭 >  Elbow Group에서 원하는 Fitting 종류를 지정한다.

 

반응형

오류원인: 

 

CrossFitting 할때 , Routing Preference가 Cross에 설정되어 있지 않다.

 

해결방법 : 

 

Element 의 Type Edit > Routing Preferences Edit 클릭 > Cross Group에서 원하는 Fitting 종류를 지정한다.

 

 

반응형

[ 목표 ]

Revit 의 PushButton 에 icon(image) 를 넣는다.

 

[ 방법 ]

 

   private void CreatePipeButton(RibbonPanel panel)
        {
            PushButtonData pbd_pipe = new PushButtonData("Pipe 생성", "Pipe 생성", executingAssemblyPath, "RevitProject.CreatePipeButton");
            pbd_pipe.LongDescription = "Pipe 자동 그리기 버튼";
            PushButton pb_pipe = panel.AddItem(pbd_pipe) as PushButton;
            pb_pipe.LargeImage = new BitmapImage(new Uri(@"C:\Users\bigan\Desktop\Icon\pipe.png"));
            pb_pipe.Enabled = true;
        }

 


[ 주의할점 ]

 

16px 이상의 그림을 넣을경우 Image 가 아닌 LargeImage 속성을 사용한다.

 

반응형

[ 목표 ]

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

 

[ 방법 ] 

 

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

 

[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    class CreatePipeButton : IExternalCommand
    {

        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 = GetPipeLine(uidoc, document);

            // Pipe 생성 및 Pipe Fitting
            CreatePipe(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 element)
            {
                return true;
            }

            public bool AllowReference(Reference refer, XYZ point)
            {
                if (doc.GetElement(refer).GetGeometryObjectFromReference(refer) is PlanarFace)
                {
                    return true;

                }
                return false;
            }
        }

 public List<Element> GetPipeLine(UIDocument uidoc, Document document)
        {
            ISelectionFilter selFilter = new PlanarFacesSelectionFilter(document);
            IList<Reference> references = uidoc.Selection.PickObjects(ObjectType.Element, selFilter, "Select multiple planar faces");
            List<Element> elementlist = new List<Element>();

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

            return elementlist;
        }

public void CreatePipe(UIDocument uidoc, Document document, List<Element> elementlist)
        {

            // (1) pipe 생성하기

            // 1-1) pipe 생성에 필요한 속성 임의로 가져오기
            PipeType pipeType = new FilteredElementCollector(document).OfClass(typeof(PipeType)).FirstElement() as PipeType;
            Level level = new FilteredElementCollector(document).OfClass(typeof(Level)).First() as Level;
            FilteredElementCollector sysCollector = new FilteredElementCollector(document);
            sysCollector.OfClass(typeof(PipingSystemType));
            ElementId pipeSysTypeId = sysCollector.FirstElementId();
            bool flag = true;

            // 1-2) 변수선언
            Pipe newpipe = 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) 트랜젝션 실행
            using (Transaction trans = new Transaction(document))
            {
                try
                {
                    trans.Start("Create pipe");

                    // 1-5) 파이프 생성 후 리스트에 담기
                    List<Line> lines = new List<Line>();
                    List<Pipe> pipes = new List<Pipe>();
                    List<Element> elePipe = new List<Element>();
                    foreach (GeometryElement geometryele in geometryElements)
                    {
                        foreach (GeometryObject obj in geometryele)
                        {
                            Line line = obj as Line;

                            lines.Add(line);


                            start = line.GetEndPoint(0);
                            end = line.GetEndPoint(1);
                            if (pipeType != null)
                            {

                                newpipe = Pipe.Create(document, pipeSysTypeId, pipeType.Id, level.Id, start, end);
                                pipes.Add(newpipe);

                                Element element = document.GetElement(newpipe.Id as ElementId);
                                elePipe.Add(element);

                                // 1-6) fitting 할 elbow 굵기에 맞게 pipe 굵기 설정하기
                                ElementId elementId = newpipe.Id as ElementId;
                                Parameter parameter = element.LookupParameter("Diameter");
                                parameter.Set(10 * 0.007333);

                                // 1-7) Pipe 의 연결할 elbow Type 지정하기
                                // Revit api 로 pipe fitting 할 경우 연결할 elbowType의 기본값이 none이기 때문에 꼭! Routing Preferences에서 설정해주어야한다.
                                ElementType elbowType = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_PipeFitting).OfClass(typeof(ElementType)).Cast<ElementType>().Where(x => x.FamilyName.Contains("M_Elbow")).FirstOrDefault();
                                RoutingPreferenceManager rpm = newpipe.PipeType.RoutingPreferenceManager;
                                rpm.AddRule(RoutingPreferenceRuleGroupType.Elbows, new RoutingPreferenceRule(elbowType.Id, "Set Elbow fitting Type"));
                                int routingPerenceGroupCnt = rpm.GetNumberOfRules(RoutingPreferenceRuleGroupType.Elbows);
                                if (routingPerenceGroupCnt > 1)
                                {
                                    for (int k = 0; k < routingPerenceGroupCnt - 1; k++)
                                    {
                                        rpm.RemoveRule(RoutingPreferenceRuleGroupType.Elbows, 0);
                                    }
                                }
                            }
                        }
                    }

                    // (2) Pipe 연결시키기 

                    // 2-1) transaction 안에서 종류 설정했으므로 중간에 새로고침하여 elbow 종류 설정한 값 적용되도록 하기 
                    document.Regenerate();
                    // 2-2) 연결시킬 2개의 파이프 connector 가져오기위해, connectormanager로 connectors 뽑아내기

                    for (int i = 0; i < pipes.Count() - 1; i++)
                    {

                        ConnectorManager pipe_connectorManager1 = pipes[i].ConnectorManager;
                        ConnectorSet pipe_connectorSet1 = pipe_connectorManager1.Connectors;
                        ConnectorManager pipe_connectorManager2 = pipes[i + 1].ConnectorManager;
                        ConnectorSet pipe_connectorSet2 = pipe_connectorManager2.Connectors;


                        // 2-3) 파이프가 가지고 있는 connectors 에서 연결시킬 connector 뽑아내기

                        Connector pipe_connector1 = null;
                        Connector pipe_connector2 = null;
                        double minDist = double.MaxValue;
                        foreach (Connector connector1 in pipe_connectorSet1)
                        {
                            foreach (Connector connector2 in pipe_connectorSet2)
                            {
                                double d = connector1.Origin.DistanceTo(connector2.Origin);
                                if (d < minDist)
                                {
                                    pipe_connector1 = connector1;
                                    pipe_connector2 = connector2;
                                    minDist = d;
                                }
                            }
                        }

                        // 2-4) 2개의 파이프 연결시키기
                        FamilyInstance fitting = document.Create.NewElbowFitting(pipe_connector1, pipe_connector2);
                    }

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

                    trans.Commit();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Pipe 간의 각도가 너무 크거나 작습니다. \n조정 후 다시 시도해주세요");
                    trans.RollBack();
                }

            }
        }

 

 

 

 

 


 [ 주의할점 ]

 

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

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

반응형

오늘 소개해드릴 곳은

원래 가려고 한 루프탑 술집이 만석이라 우연히 찾게된 술집 입니다. 

 

 

이 계단을 따라 올라가면 3층에...

 

 

 

이런 루프탑이 똬!! 사람이 없다 >< 

 

 

그런데 2층에도 아무도 없었다. 그리고 1층에도 아무도 없었다.

이건물엔 아무도 없었다.... 어디를 가도 주문하는 곳을 찾을 수 없었다.

 

아무도 없는 2층

 

돈을 내고 이용하겠다는 왜 주문을 받지를 못하니...

 

계단을 쭉 내려와 반대편으로 걸어내려가면 보이는 1층 입구로 들어가야 주인분을 만날 수 있다.

 

 

 

이곳은 와인이 주력 상품같았다.  하지만 알콜쓰레기 집하장인 우리는....

알코올이 맛이 가장 안난다는 말리부 파인애플로 통일했다.

 

 

 

사진찍기 위해 움직이는 현란한 손놀림

 

 

정돈된 모습.... ㄷㄷ....

 

 

15000원 치즈 플레이트..

처음엔 비싸다고 생각했지만

루프탑 이용료라고 생각하고 기분좋게 맛있게 먹었다

 

 

아~ 악어 너도 먹어~ 낄낄낄

ㅈㅅ...

 

 

느낄할 떈 이 올리브도 먹어봐 낄낄낄...

ㅈㅅ2

 

장난치는 치즈 크래커 제지 당하며.... 끝!

 

 

피같은 내돈주고 먹은, 에로의 총평
: 말리부 파인애플은 인위적인 파인애플 향에 인위적인 코코넛향! 
분위기 : 9시 반을 넘어가니깐 2 테이블 더 들어오긴 했지만 한산해서 매우 좋았다
가격 : 이태원이 다 그렇지 뭐... 싸진 않음
 이태원이 다 그렇지 뭐... 양 조금.. 기본 안주 프레첼은 리필가능!
다시 갈 의사 : 웨이팅 할 정도는 아니지만 한산하다면 루프탑을 또 이용할 의사는 있다

반응형

+ Recent posts