반응형

오류메세지

Starting a transaction from an external application running outside of API context is not allowed

 

원인

1. 모든 Revit API 호출은 "API context" 내에서 수행되어야
2.
 다른 thread에서 API 액세스하는 경우
3. 이러한 현상은 Form 만들고 Button.onclick 이벤트로 API 호출할 자주 발생한다.

 

해결방법

IExternalEventHandler 을 통해 외부에서 event 발생되게한다.

 

방법1. IExternalEventHandler 생성
방법2.  Execute method 시행한다.
(Execute method Revit API context에서 실행됨)

방법3. ExternalEvent 생성(방금 생성된 event handler사용)
방법4. Revit API context에서 작업을 수행해야 경우, external event 공지하기( my_external_event.Raise() 이용)

 

오류 해결방법 참고사이트

https://stackoverflow.com/questions/31490990/starting-a-transaction-from-an-external-application-running-outside-of-api-conte

 

Starting a transaction from an external application running outside of API context is not allowed

Starting a transaction from an external application running outside of API context is not allowed. cannot start transaction.

stackoverflow.com

IExternalEventHandler 생성 참고사이트

https://thebuildingcoder.typepad.com/blog/2015/12/external-event-and-10-year-forum-anniversary.html

 

External Events and 10 Year Forum Anniversary

Ten years ago today, on December 9, 2005, Jim Quanci posted the first thread on the Revit API discussion forum. This was pointed out by Revitalizer, one of the forum's chief contributors. Thank you very much for this, Revitalizer, and thank you even more f

thebuildingcoder.typepad.com

 

반응형
반응형

1) 창(window) 이 떠있어도 Revit의 다른 기능을 사용하고 싶은 경우

* show를 사용하여 window를 띄울경우, window 에서 실행하는 작업이 Revit 에 영향을 주지 못하기 때문에 ExternalEventHandler로 이벤트를 사용해주어야한다.

 

window.Show()

Revit_Window window = new Revit_Window();
WindowInteropHelper wi = new WindowInteropHelper(window);
wi.Owner = Autodesk.Windows.ComponentManager.ApplicationWindow;
window.Show();

 

 

2) 창(window) 가 열리고 닫히기 전까지 Revit 의 다른 기능을 사용하지 못하고 싶은 경우

 

window.ShowDialog()

Revit_Window window = new Revit_Window();
WindowInteropHelper wi = new WindowInteropHelper(window);
wi.Owner = Autodesk.Windows.ComponentManager.ApplicationWindow;
window.ShowDialog();

 

 

 

 

 

 

 

반응형
반응형

오류메세지

 

해결방안

 

.rte -> .rvt file 로 변경한다

반응형
반응형

방법

 

1)    Revit  속성창 들어가기( 작업표시줄에서 revit 우클릭

2)    바로가기 > 대상(T): 에서 원하는 언어로 내용 수정

 

- 영어 : Autodesk\Revit 2017\Revit.exe" /language ENU 

- 한국어 : Autodesk\Revit 2017\Revit.exe" /language KOR 

- 그외 언어

 

반응형
반응형

 

목표) 다른 프로젝트에 설정되어있는 Standard 값으로 현재 프로젝트 Standard를 변경한다

 

 

 

방법)

 

1. 복사해올 프로젝트와 붙여넣을 프로젝트를 킨다.

 

복사해올 복사한 것을 적용한 프로젝트  2 가지를 모두 키지 않는다면 이런 오류메세지가 뜬다 .

 

 

2.    붙여넣을 프로젝트에서 Manage > Transfer Project Standards 선택

 

 

3. 설정하기

- 창의 Copy from 의 우측 combobox에서 Standard 를 복사해올 요소를 선택한다.

- 현재 프로젝트의 어떤 요소에 적용할 것인지 checkbox로 선택한다.

반응형
반응형

 

[ 목표 ]

projec() 활용하여 교차하는 point 찾기

 

[ 방법 ]

XYZ tray2Direction = ((ray2.Location as LocationCurve).Curve as Line).Direction;
Xyz tray2Origin = ((tray2.Location as LocationCurve).Curve as Line).Origin;
Xyz tray3Origin = ((tray3.Location as LocationCurve).Curve as Line).Origin;
var projectLine = Line.CreateBound( tray2Origin + tray2Direction * 100, tray2Origin - tray2Direction * 100);
XYZ projectPoint = projectLine.Project (tray3Origin).XYZPoint;

 

반응형
반응형

[ 목표 ]

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을 선택해야한다.

반응형

+ Recent posts