• 沒有找到結果。

查詢模式 Planning

第五章 IFC 實例查找

5.2 查詢模式 Planning

本研究參考了 LINQ 和 Java Stream 的設計模式,引入了一種邏輯上相對簡單 的查詢模式,稱之為 Planning,其既可以實現按 ID 查找,按類別過濾等基本功能,

也可以實現按樓層劃分,按屬性劃分等較爲複雜功能。Planning 基於 Java 實現,

所以市面上任何 Java IDE 都可以對其提供優秀的支持。如:

for (Element elm : Planning ___________________.from(model)

___________________.select(Wall.class)

___________________.withProperty("ExtendToStructure")) { ____// do something with elm

}

表示選中模型中所有帶有 ExtendToStructure 屬性的牆,而:

26

for (Element elm : Planning ___________________.from(model)

___________________.select(Wall.class, Slab.class) ___________________.onStorey("b1")) {

____// do something with elm }

表示選中所有在“b1”樓的牆和樓板。兩個 Planning 亦可以鏈接起來,如:

Planning p1 = Planning.from(model).select(Wall.class);

Planning p2 = Planning.from(model).select(Slab.class);

Planning p3 = p1.or(p2);

表示在執行 p3 時,過濾條件是選擇牆或(or)板。

Planning 裏涉及到名稱查找時均使用了基於 Levenshtein Distance 的字串模糊 匹配的方式進行搜索,即 Planning 首先以全文匹配的方式查找元件,失敗後使用 模糊匹配的方式重新查找,這樣用戶不必嚴格輸入文本也可以獲得大概結果,如

“b1”、“b-1”、“B1”等輸入都可以指代名字為“b1”的地下一樓樓層。

Planning 本身是一個疊代器,其默認疊代模型里的所有實例,而用戶可以向其 中串聯過濾條件來縮小疊代範圍(交集),多個 Planning 可以并聯爲一個 Planning

(聯集),亦可以對單個 Planning 取反(差集)。Planning 的設計理念是鼓勵使用 者構建一個完整的 Planning(選擇邏輯),執行并得到自己想要的物件,然後對這 些物件操作。這樣用於獲得物件的程式碼和用於編輯物件的程式碼不會混在一起,

從視覺觀感和可維護性的角度來説更好。

27

所以說 Planning 的設計就是其内部提供的過濾條件的設計,簡單的條件比如 按 ID 過濾,按名稱過濾等不必贅述,對於非常複雜的過濾條件該如何設計是本研 究的討論重點:根據“複雜”的程度不同,有些過濾條件并不適合 Planning。比如:

// In one query expression but it is complex for (Element elm : Planning

___________________.from(model)

___________________.select(Wall.class)

___________________.withMinimumWindows(1)) { ____// do something with elm

}

// We think this is more expressive for (Element elm : Planning

___________________.from(model)

___________________.select(Wall.class)) { ____Wall wall = (Wall) elm;

____if (wall.getWindows().length > 0) { ________// this wall has windows inside ____}

}

上述兩者是針對“牆體內部是否開窗”來過濾的高級判別式的不同設計,本研究 傾向于後者的設計思路,因爲前者中的 withMinimumWindows 存在過度設計

(Overengineering)的問題,具體原因有兩點:

1)該函數存在兩個條件:最小值(Minimum)和窗體(Window),這樣勢 必意味著 Planning 需要設計 withMaximumWindows,考慮到墻體内還會存在門,

28

洞,管綫等構件,所以還必須設計 withMaximumDoors,withMaximumHoles……這 樣 Planning 的功能過於臃腫。

2)不僅是墻内可以存在窗體,板也可以(天窗),房間也可以(房間包含墻),

而事實上 IFC 并沒有規定窗必須存在于特定元件中。但沒有相關知識的一般使用 者會自然地認爲 withMinimumWindows 衹適用于墻,所以以下程式碼:

Planning.from(model).onStorey("b1").withMinimumWindows(1) // may returns Wall, Space, Door …

對他們來説會產生未預料結果(Unexpected Results),因為 Planning 可能返回了 牆以外的物件,而使用者並沒有實現對它們進行處理的程式碼。

綜上所述,本研究選擇了后一種設計方法,其它的過濾條件也都考慮了類似 的前提。截至成稿,Planning 中設計完成的過濾條件如下:

1)select:選擇單個或多個類別;

2)from:從模型中選擇;

3)withId:選擇具有特定 ID 的實例;

4)withGuid:選擇具有特定 GUID 的實例;

5)withGeometry:選擇具有幾何外觀的實例;

29

11)connectedTo:選擇與特定實例有連接的實例(如墻對墻,墻對門,墻對 空間等);

12)or:并聯其它 Planning 過濾條件。如果兩個 Planning 均 from 同一個 IFC 模型,第二個可以省略 from:

Planning p1 = Planning.from(model).select(…);

Planning p2 = Planning.onStorey(…); // also from model Planning p3 = p1.or(p2);

若兩個 Planning 各自 from 不同的模型,則 or 會執行兩個 Planning 的疊代器得到兩 個結果,并合并成一個列表:

Planning p1 = Planning.from(model_1).select(…);

Planning p2 = Planning.from(model_2).select(…);

Planning p3 = p1.or(p2);

// equivalent to:

List<Element> p3 = p1.toList().addAll(p2.toList());

此時 p3 已經失去疊代器的意義,退化成一個列表。

30

相關文件