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.BoundingBoxSolid.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);
}

总结

不总结了,写累了,完!

posted @ 2024-03-19 01:01  杂鱼Tong  阅读(20)  评论(0编辑  收藏  举报