ARCHICADBIMPython開発
IFC の情報を Excel に書き出す
2025.05.12
2025.03.21
こんにちは。
IU BIM STUDIOの原田です。
今回はIFCファイルからPythonを使ってプロパティ情報を取り出す方法を紹介します。
IFCファイルは建築業でのモデルデータの規格です。BIMに関係するソフトは多々ありますがBIMソフトのファイル同士は互換性がないなどの問題もあります。そのような場合にデータを共有したり、違うソフトで作られたモデルを統合して確認するために使います。
IFCファイルはテキストデータになっていてメモ帳で開いてみることができます。
これらはIFCのルールに則って記述されたモデルデータになります。
これをPythonで読み取って処理していくのですが、IFCの処理を簡単にするIfcOpenShellというライブラリがあります。今回はこれを使って、IFCファイルの情報を抽出していきます。
今回のモデルはArchicadのサンプルモデルをIFCに書き出したものを使用しています。
IfcOpenShellの公式サイトはこちらです
https://ifcopenshell.org/
IfcOpenShellをインストールします。
pip install ifcopenshell
まずはファイルを開きます
import ifcopenshell
model = ifcopenshell.open("sample.ifc")
次にIFCタイプごとにモデル要素を取得します
walls = model.by_type("IfcWall")
これで全てのIfcWall要素がとりだせます。
Archicadを使用しているときに見落としやすいのが壁ツールを使って作ったものが全てIfcWallではないということです。
ArchicadではIfcにどのように書き出すかは分類やIFC変換設定によって決まります。分類の設定をきちんとしないと建物のデータとして役に立たないこともありますので注意が必要です。
モデル要素をfor文でひとつずつ処理していきます
要素の名前などを取得するには下記のようにします。
for wall in walls:
# 基本的な情報を取得
name = wall.Name
guid = wall.GlobalId
tag = wall.Tag
print(f"{name}, {guid}, {tag}")
# ALCt100, 3JFMZDCaP2RBUd74eMmQBP, D33D68CD-3246-426C-B7A7-1C4A16C1A2D9
名前は要素の名前でArchicadでは要素IDが出力されます。GlobalIdはIFC要素のユニークID、TagはArchicadでのユニークIDです。
もう少し情報を見るには次のようにします
for wall in walls:
# 要素の情報を取得
info = wall.get_info()
print(info)
# {'id': 18478, 'type': 'IfcWall', 'GlobalId': '3JFMZDCaP2RBUd74eMmQBP', 'OwnerHistory': #2=IfcOwnerHistory(#6,#7,$,.NOCHANGE.,$,$,$,1738742917), 'Name': 'ALCt100', 'Description': None, 'ObjectType': None, 'ObjectPlacement': #41419=IfcLocalPlacement(#31274,#133433), 'Representation': #7105=IfcProductDefinitionShape($,$,(#849,#3194)), 'Tag': 'D33D68CD-3246-426C-B7A7-1C4A16C1A2D9'}
IfcWall要素が持っている情報を取得できます。
idはIFCの行頭についている番号で#がついている数字です。
取り出した壁の情報の中にたくさん#があることからもわかるようにIFCはルールで定義された要素を参照しあって複雑な建築情報を記述しています。
例えばIfcLocalPlacementにはモデル要素の位置情報が、IfcProductDefinitionShapeには形状情報が記述されています。
詳しいことはBuilding Smartの仕様標準から見ることができます。
IFC2x3の場合は下記から見ることができます。
https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/
壁の形状情報はRepresentationの中に入っており、その中から形状情報を取り出すことができます。
下記は壁の基準線を取り出す方法の例です。
for wall in walls:
# 壁の形状情報を取得の例
try:
start_point = (
wall.Representation.Representations[1].Items[0].Points[0].Coordinates
)
end_point = (
wall.Representation.Representations[1].Items[0].Points[1].Coordinates
)
except Exception:
start_point = None
end_point = None
print(start_point, end_point)
# (0.0, 0.0) (1520.000000000004, 0.0)
例というのはIFCでは常にこの方法で基準線を取り出すことはできないためです。
IFCは押出形状、Brepと様々な形状の記述方法ができますが、いろいろできるからこそ決まったデータの取り出し方がありません。
ArchicadでIFCをインポートした時にモデルがオブジェクトになってしまったりする原因の一つはここらへんにあります。
今回は練習のため、エラーは無視してしまいましょう。
形状を取り出すには次のような書き方もできるようです。
import ifcopenshell.util.representation
try:
axis = ifcopenshell.util.representation.get_representation(
wall, "Model", "Axis"
)
start_point2 = axis.Items[0].Points[0].Coordinates
end_point2 = axis.Items[0].Points[1].Coordinates
except Exception:
start_point2 = None
end_point2 = None
こちらもIFCの中で”Aixs”というラベルを付けたデータとして入っている必要があるため、BIMソフトによって記述方法が違うなどの可能性があり注意が必要です。
上記の基準線情報を取得すると全ての壁の始点が0から始まっていることが分かります。(書き出したBIMソフトによるかもしれませんが)
でも、モデルを見ると全ての壁が同じ点にはありません。
これはなぜかというと、IFCでの基準線の記述方法がモデル要素の位置情報に対しての相対座標になっているためです。
その基準となる位置情報は下記のように取得します。
for wall in walls:
# 壁の位置情報を取得の例
place = wall.ObjectPlacement.RelativePlacement.Location.Coordinates
print(place)
# (18300.0, -350.0000000000031, 300.0)
ただこの位置情報も階や敷地などいろいろな位置情報を参照しているためモデルの空間上での正しいとは限りません。
実際の座標を取得するには下記のようにします。
import ifcopenshell.util.placement
for wall in walls:
# 壁の絶対位置情報を取得
local_placement = ifcopenshell.util.placement.get_local_placement(wall.ObjectPlacement)
print(local_placement[:, 3][:3])
# [18300. -350. 400.]
get_local_placement関数はnumpyの行列で返ってきますので、座標部分のみを取り出します。
Zの値が400になっています。これは階のレベルが+100で壁の下端がFL+300だったためですね。
配置階を取得するには下記のようにします。
import ifcopenshell.util.element
for wall in walls:
# 壁の配置階を取得
container = ifcopenshell.util.element.get_container(wall).Name
print(container)
# 1FL
分類を取得するには下記のようにします。
import ifcopenshell.util.classification
for wall in walls:
# 壁の分類情報を取得
references = ifcopenshell.util.classification.get_references(wall)
for reference in references:
if reference.ReferencedSource.Name == "ARCHICAD 分類":
classification_name = reference.ItemReference
print(classification_name)
# 壁
get_referencesはsetで返ってきます。分類が複数ある場合はfor文で目的の分類システムの場合の値を取得します。
プロパティは下記のように取得します。
for wall in walls:
# 壁のプロパティ情報を取得
property = ifcopenshell.util.element.get_psets(wall)
print(property)
# {'仕上情報': {'WEBサイト': 'www.graphisoft.co.jp', 'id': 133435}, 'ArchiCADProperties': {'壁形状': '直線', '図形作成法': '均一', '基準線位置': '躯体中心', '内面材質': '漆喰 - 白 ファイン', '外面材質': '漆喰 - 白 ファイン', '壁内側傾斜角度': 90.0, '壁外側傾斜角度': 90.0, '要素ID': 'ALCt100', 'ホットリンク および要素ID': 'ALCt100', 'レイヤー': '壁-躯体', 'ユニークID': 'D33D68CD-3246-426C-B7A7-1C4A16C1A2D9', 'Archicad IFC ID': '3JFMZDCaP2RBUd74eMmQBP', 'ビルディングマテリアル/複合構造/断面形状/塗りつぶし': '壁: ALC t100', '複合構造': '壁: ALC t100', ...
Pythonでifcopenshellを使ってIFCモデルの情報を取り出す基本的な方法を紹介しました。
ifcopenshellを使うことでIFCのデータを利用することができます。
ただ、いろんなデータの記述ができるため、ソフトウェア側で対応するのは大変な部分もあります。
うまく使ってIFCのデータを有効活用できるようになりましょう。
以下に今回のコード全文を載せておきます。
import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.util.classification
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.representation
import ifcopenshell.util.shape
def main():
model = ifcopenshell.open("sample.ifc")
walls = model.by_type("IfcWall")
for wall in walls:
# 基本的な情報を取得
name = wall.Name
guid = wall.GlobalId
tag = wall.Tag
print(f"{name}, {guid}, {tag}")
# 要素の情報を取得
info = wall.get_info()
print(info)
# 壁の形状情報を取得の例
try:
start_point = (
wall.Representation.Representations[1].Items[0].Points[0].Coordinates
)
end_point = (
wall.Representation.Representations[1].Items[0].Points[1].Coordinates
)
except Exception:
start_point = None
end_point = None
print(start_point, end_point)
# 形状を取得の例2
try:
axis = ifcopenshell.util.representation.get_representation(
wall, "Model", "Axis"
)
start_point2 = axis.Items[0].Points[0].Coordinates
end_point2 = axis.Items[0].Points[1].Coordinates
except Exception:
start_point2 = None
end_point2 = None
print(start_point2, end_point2)
# 壁の位置情報を取得
place = wall.ObjectPlacement.RelativePlacement.Location.Coordinates
print(place)
# 壁の絶対位置情報を取得
local_placement = ifcopenshell.util.placement.get_local_placement(
wall.ObjectPlacement
)
print(local_placement[:, 3][:3])
# 壁の配置階を取得
container = ifcopenshell.util.element.get_container(wall)
floor_name = container.Name
elevation = container.Elevation
print(f"{floor_name}, {elevation}")
# 壁のプロパティ情報を取得
property = ifcopenshell.util.element.get_psets(wall)
print(property)
# 壁の分類情報を取得
references = ifcopenshell.util.classification.get_references(wall)
for reference in references:
classification_system = reference.ReferencedSource.Name
if classification_system == "ARCHICAD 分類":
classification_name = reference.ItemReference
print(f"{classification_system} : {classification_name}")
if __name__ == "__main__":
main()