• 沒有找到結果。

IFC 實例編輯

一直以來對於 IFC 模型的編輯問題,業界內的討論較少。這主要是因為 IFC 作為交換模型本身需要修改的情境不多,即便需要修改,也是在上游軟體內先完 成,再重新匯出為 IFC。雖然 STEP 的最初設計是考慮到人類可讀可改的,但是隨 著 IFC 標準發展到現在,其複雜的結構早已使編輯變得非常棘手。

但即便是少數情況,具備 IFC 模型修改的能力也是非常必須的,例如設施運 營維護時,針對某個特定元件新增的資料屬性參數,該值並不一定需要回到源模 型中,但如果沒有相應的 IFC 編輯能力,維護人員只能:

1)修改源模型添加該值再匯出為新的 IFC 模型;

2)將該值存儲於其他容器如資料庫或 Excel。

這兩種方法,一個是變動了源模型,且重新匯出費時費力;另一個需要依靠外部 容器,增加了運營成本。

6.1 幾何參數編輯

對於幾何模型的編輯,本文認為難度較大,但這並不是從 SDK 設計角度而言 的難度,而是與前一章開頭提到的 GUI 有關——即在沒有圖形介面的情況下,用 戶通過程式創建、修改 3D 網格面片模型是極其複雜的,這種複雜性包含兩點:

1)用戶需要具備基本的圖形學的知識。雖然用戶並不需要親自實現各種相關 函數,但至少它們需要懂得每個函數是幹什麼的才能調用;

2)就算最終生成模型,也還是要依靠 GUI 介面才能展現。特地只使用程式碼 修改 3D 模型的行為本身並沒有太大意義。

31

目前市面上確實存在一些“程式化模型編輯軟體”,比如 Dynamo12(圖 12)

和 OpenSCAD13(圖 13)。但需要注意的是它們並不是嚴格意義上的“SDK”而 是一套“工具”。從設計理念上來說,SDK 並不等價於工具——工具應該是基於 SDK 的更高級的應用。

圖 12 OpenSCAD 圖 13 Dynamo

本研究的 SDK 只提供了四個基本的 API 進行操作:

1)replaceGeometry:用某個已經存在的模型的多邊形網格替換另一個元件的 網格。如用戶新建一面牆,則做法是構建一面空牆,再將一面已有的牆的幾何外 觀複製到該空牆上,或從 obj、ifc 等外部模型導入網格作為其外觀。

2)descendToBoundingBox:降低模型面數。即使用一個立方體替換原有元件 的 3D 網格,該立方體三維尺寸等同於原元件的邊界範圍(Bounding Box)。

3)descendToMesh:對於 IFC 内定義的參數幾何外觀(擠出 Extrude、掃掠 Sweep 等),將其轉變爲純粹的多邊形網格。

4)transform:改變模型在坐標系中的位置,位置(Location)資訊包含:位 移(Translation)、旋轉(Rotation)和縮放(Scale)。

12 http://dynamobim.org/

13 http://www.openscad.org/

32

對於一些特殊情況,比如任何具有 IfcExtrudedAreaSoild 外觀的幾何體,用戶 可以修改擠出(Extrude)高度;對於 IfcProfileDef 裏的常規曲線比如矩形,圓,

用戶也可以編輯其中的一些參數。

本 SDK 提供了 Mesh、Face、Vector、Matrix 等涉及圖形學的基礎類別,但不 會承擔上述 API 以外的更為複雜的模型編輯功能。

6.2 非幾何參數編輯

對於非幾何資料的編輯主要基於 IFC 的 IfcProperty 類別,但如前文所述,IFC 裏屬性參數是不附加在元件身上的而是通過關係鏈接,所以 SDK 裏專門提供了 Property 類別抽象化 IfcProperty 以及關係鏈接 IfcRelDefines。

Property 本身是一個 Key-Value 容器,代理儲存了原來在 IfcSimpleProperty 裏 的參數資訊。使用了 Property 以後,對於參數的獲取、增添和刪除就變成了 Java 內 置 的 Map 容 器 的 get 、 add 和 remove , 其 中 key 是 String 類 型 , value 是 Property.Value 類型。這簡化了程式邏輯,也極大地減輕了用戶的負擔,如以下示 例程式碼演示了獲取墻的 Phase 參數,并修改爲 2。

Wall w = Planning.from(model).select(Wall.class).toList().get(0);

Property.Value phase = w.getProperty().get("Phase");

phase.setValue(2);

w.getProperty().put("Phase", phase);

但這其中存在不少特殊情況需要處理,比如房間(Space)的面積(Area)等 相關參數,它們由 IfcElementQuantity 記錄,該類別是 IfcProperty 的子類別,但是

33

在 SDK 中這些參數的操作并不會由 Property 類別處理,而是交由 Space 類別内部 的專門獲取函數(Getter)如 getArea。這樣的設計考慮了兩點:

1)Property.Value 是可修改的(Mutable),但不改變幾何外觀而直接修改面 積、體積等幾何參數并沒有太大意義。所以 SDK 不用 Property 類別封裝這些參數,

同時也衹提供 Getter 函數而不提供 Setter。

2)在某些情況下,從軟體匯出的 IFC 里的 IfcSpace 實例并沒有對應的 IfcElementQuantity 參數,但空間的面積體積等幾何參數是確實存在的,所以 getArea 仍會基於其幾何形狀計算一個近似值。

最後,SDK 裏的非抽象類別(即不是 Element、GeoElement、SpatialElement 的類別)都可以實例化,這一點設計不同於 Revit API。在 Revit 的 API 中,我們 所看到的 Element 及其派生類別並不真實存在——它們的底層是 ElementProxy。因 为 Revit 主程式裏的元件基於 C++,API 必须通過 ElementProxy(C++/CLI)將它 們與 C#裏的元件關聯起來,所以在 Revit API 中并不能實例化一面墻(new Wall),

而是必須由 Revit 主程式建立一面墻,然後用 API“獲得”它。但从物件导向的理 念来说,这样的设计不符合用户直觉。本研究并不需要考慮兩種語言之間物件傳 遞的問題,SDK 的設計也盡量貼合了語義表達:

Wall w = new Wall("new wall");

w.replaceGeometry(anotherWall.getGeometry()).transform(…);

model.addElement(w);

上述程式碼構建了一面新牆,名稱為“new wall”,其幾何外觀從另一面牆複製,

最後該牆被添加進模型中。

34

相關文件