Revit获取元素Solid和计算包围盒
Revit获取元素Solid和计算包围盒
前言
Revit插件开发中,获取元素Solid和准确获取元素的包围盒是很有用的。比如说直接获取的包围盒可能很大,会有BoundingBoxIntersectsFilter
过滤不准的问题,若能够“准确”的获取包围盒,就可以解决这个问题。
在过去一段时间的插件开发过程中,获取元素包围盒这部分出过几次错,挺有意思的,便写一写这方面的知识。
获取元素的所有Solid
获取Solid
要准确获取元素的包围盒,需要先获取到该元素的所有Solid,这里先讲一下元素Solid的获取。
查看Revit API文档,搜索
Solid
,有代码示例。
首先,我们得知道获取元素Solid的方法:
// 选自Revit API Solid class示例
// Get geometry element of the selected element
Autodesk.Revit.DB.GeometryElement geoElement = element.get_Geometry(geoOptions);
get_Geometry
方法要求要填写一个Options
类型参数,这里不展开。
Options
属性,请查看API文档。其各属性设置效果,请使用RevitLookup
插件查看。
至此,我们就能够获取到元素的Solid了。但是这并不够,一个元素是可能存在嵌套族的,所以我们还需要获取到嵌套族的Solid才行。
说到这里,就需要用到上一篇《获取元素的嵌套族》中的知识了。
获取到嵌套族,再获取嵌套族的Solid,这样就能拿到元素所有Solid了。
问题点记录
以下代码是获取元素本身Solid的递归部分,其中有几个问题点需要注意。
// 获取元素Solid
private static void GetSolidsFromElement_Recursion(GeometryElement geometryElement, ref List<Solid> solids)
{
foreach (GeometryObject geomObj in geometryElement)
{
if (geomObj is Solid solid)
{
if (solid.Faces != null && solid.Faces.Size > 0) // && solid.Edges != null && solid.Edges.Size > 0
{
solids.Add(solid.Clone());
}
}
else if (geomObj is GeometryInstance geometryInstance)
{
//GeometryElement transformedGeomElem = geometryInstance.GetInstanceGeometry(geometryInstance.Transform);
GeometryElement transformedGeomElem = geometryInstance.GetSymbolGeometry(geometryInstance.Transform); // apply transform
GetSolidsFromElement_Recursion(transformedGeomElem, ref solids);
}
}
}
示例代码上有两处注释,第一处是过滤掉空Solid,第二处是矩阵转换。
注释2:应使用
GetSymbolGeometry(transform)
,不能使用GetInstanceGeometry(...)
,至于原因,说实话我没看懂API文档讲了个啥,懂的小伙伴可以评论下。注释1:不可使用
Solid.Edges
进行判断!虽然示例文档用了,但那不行,因为Solid可以没有边
。
上面提到“Solid可以没有边“,怎么回事儿呢?
这就涉及到Revit模型的表示方法了,B-Rep
(Boundary representation)表示法,这是后话了,总之不可以就是了。
P.S.(有个锤子的后话,本来是想写写,查查资料发现没看懂,算了算了ㄟ( ▔, ▔ )ㄏ)
举个例子:圆轮廓的闭合圆形放样
(甜甜圈)就没有边,只有面。
元素包围盒
当我们知道如何获取到元素的Solid后,我们就可以“准确”
计算出元素的包围盒了。
“准确”:指的是实际Solid组成的包围盒。
Element.BoundingBox
和Solid.GetBoundingBox()
是不同的。
element.get_BoundingBox()
:一个“可放置族”,族内部可能存在不可见的元素,这些物体也会参与到包围盒计算中,导致最终计算出的包围盒可能要大很多,而不是预期的刚好包住模型面。
// 部分代码
// 遍历所有Solid
foreach (Solid solid in solids)
{
BoundingBoxXYZ box = solid.GetBoundingBox();
Transform transform = box.Transform;
XYZ boxMinTransform = transform.OfPoint(box.Min);
XYZ boxMaxTransform = transform.OfPoint(box.Max);
min = min.Min(boxMinTransform).Min(boxMaxTransform); // xx.Min(xx)是扩展方法,就是对三个点都取小的
max = max.Max(boxMinTransform).Max(boxMaxTransform);
}
总结
不总结了,写累了,完!