.ifc を .ifcx (ifcx_alpha) に変換する

ifcx の alpha 版 が 2025年4月に公開されたので遊ぼう!ということでデータを作ります。
追記:このコミットの alpha 版で実施

ifcx の 公式ビューアーはここにあるので、作って表示できるようにするぞー!

公式には一つしかサンプルがないけど、データ構造としては header
, schemas
, data
で構成されている。
スキーマも必須なのかなと思って削除してビューアーで表示してみたらエラーだったので必須っぽい。
"header": {
"version": "ifcx_alpha",
"author": "authorname",
"timestamp": "time string"
},
"schemas": {
... schemas
},
"data": [
... data
]

スキーマは、 データの attributes
の値の定義をしているっぽい。
この例だと bsi::name
は 文字列ですよって定義。
"schemas": {
"bsi::name": {
"value": {
"dataType": "String"
}
},
"data": [
{
"identifier":"8134f9ec-2e87-4b70-a538-9b6dc7ba94b1",
"inherits": {
"windowType": "f40ec978-42e6-414a-a044-b6df23dfafef"
},
"attributes": {
"bsi::name": "Instance of Window_001"
}
},

ifcx のファイル内のスキーマではなくて、先に ifcx 自体のスキーマを見ましょうね。
ということでこれです。ifc-alpha.tsp
ifcx のファイル自体は header
, schemas
, data
で構成されている。
メインの data
は IfcxNode
のリスト。
model IfcxFile {
header: IfcxHeader;
schemas: Record<IfcxSchema>;
data: IfcxNode[]
}
IfcxNode
は以下。id とノードの子(children
, inherits
) と 属性がある。
children
, inherits
の違いはひとまず気にしないでおく。
model IfcxNode {
identifier: path;
children?: Record<string | null>;
inherits?: Record<string | null>;
attributes?: Record<unknown>;
}

children
は tree の表示的な子要素な感じ。

inherits
は 今あるサンプルデータ だと WindowType のみ。
IFCファイルでの リレーションに相当するものかなとも思ったけど、 attribute にその要素があったりもするから、何が入ってくるのかよくわからない。現状だと IfcRelDefinesByType
だと思っておけばいいかな。

形状情報は、三角形メッシュがそのまま入っているので作るのは簡単そう。

tree 構造は children
に入れるだけだからこれも簡単にできる。
IFCファイルから作るのであればこれだけ。
model = ifcopenshell.open(path)
project = model.by_type("IfcProject")[0]
root_node = {"identifier": str(uuid.uuid4()), "children": {}}
nodes = [root_node]
project_node = {"identifier": str(uuid.uuid4()), "children": {}}
nodes.append(project_node)
root_node["children"][project.Name or project.GlobalId] = project_node["identifier"]
def add_children_node(nodes, element, node):
children = ifcopenshell.util.element.get_decomposition(element, is_recursive=False)
for child in children:
child_node = {"identifier": str(uuid.uuid4()), "children": {}}
nodes.append(child_node)
node["children"][child.Name or child.GlobalId] = child_node["identifier"]
add_children_node(nodes, child, child_node)
add_children_node(nodes, project, project_node)

usd::usdgeom::mesh
追加して形状情報追加して公式ビューアーで表示しようとしたらエラーになった。
render.mjs:459 Uncaught TypeError: Cannot read properties of undefined (reading 'usd::usdshade::materialbindingapi::material::binding')
usd::usdshade::materialbindingapi::material::binding
は必須なのか。適当にデフォルト色を入れてくれればいいんだけど、そんな機能はないっぽい。

色情報はこれ。id に /
入っているのは気持ち悪いので参考にしないようにします(?)。
というより色情報だけ特殊処理しないといけなくなるから修正されると思う。
{
"identifier":"359c715f-5961-4c20-be08-9bb25ea75c24/Shader",
"attributes": {
"bsi::name": "WallMaterial shader",
"usd::materials::info::id": "UsdPreviewSurface",
"usd::materials::inputs::diffuseColor": [
0.8,
0.7,
0.6
],
"usd::materials::inputs::opacity": 1,
"usd::materials::outputs::surface": null
}
},

色の指定は、データ構造的にはこうなんだけどさ。これ、窓みたいに、ガラスと木枠の2種類で構成されてるときって、色指定個別にできなくない?Bodyの方に色情報つけないと。

ひとまず気にせず色設定をしよう。
オブジェクトの属性に usd::usdshade::materialbindingapi
がついてて、
{
"identifier":"f079bafd-8733-48d8-85df-1c1656a17c1f",
"attributes": {
"usd::usdshade::materialbindingapi": {
"material::binding": {
"ref": "f83b2e90-81df-4cae-ad63-52a51009e561"
}
},
}
},
usd::usdshade::materialbindingapi
に usd::usdshade::material
? が紐づいていて、
{
"identifier":"f83b2e90-81df-4cae-ad63-52a51009e561",
"children": {
"Shader": "b3325921-8f14-4847-9473-cfc6e333683a"
},
"attributes": {
"bsi::name": "SpaceMaterial",
"usd::usdshade::material": {
"outputs::surface.connect": {
"ref": "./Shader.usd::materials::outputs::surface"
}
}
}
},
その下に色情報が紐づいている形。
{
"identifier":"f83b2e90-81df-4cae-ad63-52a51009e561/Shader",
"attributes": {
"bsi::name": "SpaceMaterial shader",
"usd::materials::info::id": "UsdPreviewSurface",
"usd::materials::inputs::diffuseColor": [
0.6,
0.7,
0.8
],
"usd::materials::inputs::opacity": 0.3,
"usd::materials::outputs::surface": null
}
},

いけた。opening 除いてないから窓が埋まってるけど。

さて複数色を対応できるようにしますか。
複数色使ってるものは直接形状を指定するのではなくて、もう一つ階層を作って、色ごとにオブジェクトを分ける想定なんだと思う。

できた。属性情報入れてないんだけどね。

属性情報とか入れようかと思ったけど、大量にスキーマ定義しないといけないから、やめておきましょうか。まだ alpha版が出たばっかで公式が変わる可能性も高いし。
そんなわけでこのスクラップはCloseですの。