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);
}
總結
不總結了,寫累了,完!