【Revit二次开发】链接模型坐标系/族坐标系与模型坐标系转换

前因:因做管线分布时,参照线选择Revit链接文件中的构件(墙,梁,柱,管等)后,调整的管距离参照线的距离不对,经测试是坐标系不同导致。查了很多资料,故总结如下

 

Revit中坐标系有哪几种(原文链接:https://blog.csdn.net/JoeXiongjin/article/details/8202910

模型坐标系: 也理解为全局坐标系

视图坐标系:与模型坐标系之间的转换

族坐标系: 在制作族有一个坐标系,族插入到模型中,其中的几何体有自己在模型中的位置,需要进行模型坐标系的转换。

链接模型坐标系: 链接模型的位置在host模型中的位置,需要坐标转换。

 

如何进行坐标转换

使用Transform进行坐标转换,在叶雄进老师的博客中描述有三种获得Transform的方法,

1. 自己创建一个转换矩阵:

2. 直接从Revit的对象获得转换矩阵。

3. 从视图中获取视图到全局坐标系的坐标转换。

我只会用第二种(从Revit的对象获得转换矩阵),以下举两个自己遇到的两个例子用作说明

 

链接模型坐标系转模型坐标系(这段代码的目的是选取链接文件中的墙,然后得到链接文件中构件对象的trans,最后转换墙的curve的两点坐标,然后打印出来,打印出来的坐标就是模型坐标)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.DB;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;

namespace WindowTest
{
    [Regeneration(RegenerationOption.Manual)]
    [Transaction(TransactionMode.Manual)]
    public class Class1 : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            Document revitDoc = commandData.Application.ActiveUIDocument.Document;  
            Application revitApp = commandData.Application.Application;             
            UIDocument uiDoc = commandData.Application.ActiveUIDocument;

            Reference reference1 = uiDoc.Selection.PickObject(ObjectType.LinkedElement, new SelectionLinkFilter(revitDoc),"请选择一个链接参照构件");
            Transform trans = null;
            if (reference1 != null)
            {
                // get RevitLinkInstance
                Element ele2 = uiDoc.Document.GetElement(reference1);
                RevitLinkInstance linkInstance = ele2 as RevitLinkInstance;
                trans = linkInstance.GetTransform(); //get trans


                Document linkDoc = null;
                linkDoc = linkInstance.GetLinkDocument();
                Element wall = linkDoc.GetElement(reference1.LinkedElementId);
                Line line_test = (wall.Location as LocationCurve).Curve as Line;
                XYZ wallLineStartPoint = line_test.GetEndPoint(0);
                XYZ wallLineEndPoint = line_test.GetEndPoint(1);
                if (wall is Wall)
                {
                    TaskDialog.Show("wallStartPoint", wallLineStartPoint.ToString());
                    TaskDialog.Show("wallEndPoint:", wallLineEndPoint.ToString());
                    TaskDialog.Show("Trans_wallStartPoint", trans.OfPoint(wallLineStartPoint).ToString());
                    TaskDialog.Show("Trans_wallEndPoint", trans.OfPoint(wallLineEndPoint).ToString());
                }
                else
                {
                    TaskDialog.Show("ERROR", "请勿选择非墙的元素!");
                    return Result.Failed;
                }
            }
            return Result.Succeeded;
        }       
    }

    //外链接过滤器
    public class SelectionLinkFilter : ISelectionFilter
    {
        public RevitLinkInstance rvtIns;
        private readonly Document _doc;
        Document linkDoc = null;

        public SelectionLinkFilter(Document doc)
        {
            _doc = doc;
        }
        public bool AllowElement(Element elem)
        {
            if (elem is RevitLinkInstance)
            {
                linkDoc = (elem as RevitLinkInstance).GetLinkDocument();
                rvtIns = elem as RevitLinkInstance;
                return true;
            }
            return false;
        }

        public bool AllowReference(Reference reference, XYZ position)
        {
            //TaskDialog.Show("reference.LinkedElementId", linkDoc.GetElement(reference.LinkedElementId).GetType().ToString());
            if (linkDoc.GetElement(reference.LinkedElementId) is Wall)
            {
                //TaskDialog.Show("RevitLinkInstance", (_doc.GetElement(reference) is RevitLinkInstance).ToString());
                return true;
            }
            return false;
        }
    }
}

族坐标系转模型坐标系(这段代码的目的是选取柱子的一条边(备注:柱子是族实例),然后得到柱子的几何实例对象的Trans,最后对选取的柱子的这条边进行转换,最后得到的坐标就是模型坐标)

要想清楚知道族坐标和模型坐标之间的关系的,可以查看叶雄进老师的这篇文章                                                                          文章链接:https://blog.csdn.net/JoeXiongjin/article/details/16883451

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.DB;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;

namespace WindowTest
{
    [Regeneration(RegenerationOption.Manual)]
    [Transaction(TransactionMode.Manual)]
    public class GetFamilyInstanceTrans : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            Application revitApp = commandData.Application.Application; 
            UIDocument uiDoc = commandData.Application.ActiveUIDocument;
            Document revitDoc = commandData.Application.ActiveUIDocument.Document; 

            Selection S2 = uiDoc.Selection;
            Reference re = null;
            try
            {
                re = S2.PickObject(ObjectType.Edge, "请选择柱的一条边:");
            }
            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                return Result.Failed;
            }

            if (re != null)
            {
                FamilyInstance col = revitDoc.GetElement(re) as FamilyInstance;
                //GetGeometryObjectFromReference     obtain an edge selected by user
                Edge geo_edge = revitDoc.GetElement(re).GetGeometryObjectFromReference(re) as Edge;
                Curve cur_geo = geo_edge.AsCurve();

                Options opt = new Options();
                opt.ComputeReferences = false;
                opt.View = revitDoc.ActiveView;
                GeometryElement geoElement = col.get_Geometry(opt);
                Line transColumeEdge = null;   //转换后的柱子的一条边

                Transform trans = null;
                foreach (GeometryObject geo_Obj in geoElement)
                {
                    if (geo_Obj is GeometryInstance)
                    {
                        GeometryInstance geoInst = geo_Obj as GeometryInstance;
                        trans = geoInst.Transform;
                        break;
                    }
                }
                if (trans != null)
                {
                    XYZ edge_start = cur_geo.GetEndPoint(0);
                    XYZ edge_end = cur_geo.GetEndPoint(1);
                    XYZ trans_edgestart = trans.OfPoint(edge_start);
                    XYZ trans_edgeend = trans.OfPoint(edge_end);
                    transColumeEdge = Line.CreateBound(trans_edgestart, trans_edgeend);
                }
            }
            return Result.Succeeded;
        }
    }
}

总结:不管是链接模型坐标系还是族坐标系,要想要转换其中坐标为模型坐标的核心就是得到实例对象的TransForm,链接模型是reference ->Element—>RevitLinkInstance。族是得到reference—>Element—>FamilyInstance—>GeometryElement—>GeometryInstance.Transform。

 

2019.11.27日补充:

当一个Revit项目中存在一个Revit链接模型,Revit链接模型中有一个柱子(族),要想获得柱子的某一边的坐标需要进行的坐标转换步骤如下,首先,获得族实例的Trans,然后进行第一次转换,然后获得链接文件的Trans,将第一步获得的结果进行第二次转换。经过两次转换后才能得到柱子上某点的模型坐标。(此结果花了大半天才总结出来,虽然简单,以此告诫自己,做事情首先思考,明明很简单的转换关系,不思考,一点一点的试,费时费力!)

你可能感兴趣的:(Revit二次开发,C#)