IU Tips

IFCモデルの情報をPythonで取り出す【IfcOpenShell】

2025.03.21

こんにちは。
IU BIM STUDIOの原田です。

今回はIFCファイルからPythonを使ってプロパティ情報を取り出す方法を紹介します。

IFCとは

IFCファイルは建築業でのモデルデータの規格です。BIMに関係するソフトは多々ありますがBIMソフトのファイル同士は互換性がないなどの問題もあります。そのような場合にデータを共有したり、違うソフトで作られたモデルを統合して確認するために使います。

IFCファイルはテキストデータになっていてメモ帳で開いてみることができます。
これらはIFCのルールに則って記述されたモデルデータになります。

これをPythonで読み取って処理していくのですが、IFCの処理を簡単にするIfcOpenShellというライブラリがあります。今回はこれを使って、IFCファイルの情報を抽出していきます。

今回のモデルはArchicadのサンプルモデルをIFCに書き出したものを使用しています。

IfcOpenShellの公式サイトはこちらです
https://ifcopenshell.org/

IfcOpenShellのインストール

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()