前因:因做管线分布时,参照线选择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,将第一步获得的结果进行第二次转换。经过两次转换后才能得到柱子上某点的模型坐标。(此结果花了大半天才总结出来,虽然简单,以此告诫自己,做事情首先思考,明明很简单的转换关系,不思考,一点一点的试,费时费力!)