IU Tips

Tapirアドオンを使ってみよう【Archicad】

2025.10.29

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

今回はTapirというArchicadのアドオンを使ってみたいと思います。

Tapirとは

TapirはArchicadのアドオンでGithubで公開されています。ArchicadのPython APIはまだまだ機能が少なくモデル要素の操作などができませんが、このアドオンを使うとPythonなどで使えるコマンドが追加され、できることが増えます。

Tapirの基本的な仕組み

TapirはArchicad JSON interfaceを使ってpythonからJSONデータを仲介としてArchicad側に命令を出し、データを取得したりデータの編集をしたりすることができます。ただし、何でもできるわけではなく、どのような処理を実行するかはアドオン側で定義されている必要があります。

現状Tapirも全てのコマンドを用意しているわけではなありません。モデルを作成することもできますが、一部のものに限ります。Tapirの対応している処理はこちらで確認することができます

https://enzyme-apd.github.io/tapir-archicad-automation/archicad-addon

Tapirの基本的な使い方

TapirはPython API からArchicadにJSONを受け渡すことによって処理を行ったり、情報を取得したりすることができます。なのでTapirを使うための関数を用意しておきます。

from archicad import ACConnection

conn = ACConnection.connect()
acc = conn.commands
act = conn.types

def run_tapir_command(command: str, param: dict= None) -> dict:
    addOnCommandId = act.AddOnCommandId("TapirCommand", command)
    result = acc.ExecuteAddOnCommand(addOnCommandId, param)
    return result

コマンドによっては入力用のパラメーターを送信する必要が無いので、paramのデフォルト引数をNoneとしておくと楽でしょう。

そして、呼出し時は下記のように使用します

result = run_tapir_command("GetArchicadLocation")
print(result)

# {'archicadLocation': 'C:\Program Files\GRAPHISOFT\Archicad 28\Archicad.exe'}

戻り値は辞書型で返ってきますので、値を取り出して使用します。

Tapirでモデルを作成する

では、Tapirを使って簡単なモデルを作成してみましょう。
まずは柱を作ってみます。

def create_columns(x_list: list[float], y_list: list[float]) -> None:
    positions = []
    for x in x_list:
        for y in y_list:
            position = {
                "coordinates": {
                    "x": x,
                    "y": y,
                    "z": 0,
                }
            }
            positions.append(position)

    param = {"columnsData": positions}
    run_tapir_command("CreateColumns", param)

x_list = [i * 6 for i in range(10)]
y_list = [i * 4.5 for i in range(5)]

create_columns(x_list, y_list)

柱を作るための関数をあらかじめ作成しておきます。
関数内ではxとyの座標を指定のフォーマット通りになるよう辞書に格納していき、最後にrun_tapir_command関数でArchicadに送信します。

関数を使用するときは、xとyのリストを作成してからcreate_columns関数に渡します。
これで、作成したリストの位置に柱を作成できます。

次に、柱の範囲から少し広げた大きさのスラブを作ってみたいと思います。

def create_polygon_coords(
    x_list: list[float], y_list: list[float], distance
) -> list[dict]:
    min_x = min(x_list) - distance
    max_x = max(x_list) + distance
    min_y = min(y_list) - distance
    max_y = max(y_list) + distance

    coords = [
        {"x": min_x, "y": min_y},
        {"x": max_x, "y": min_y},
        {"x": max_x, "y": max_y},
        {"x": min_x, "y": max_y},
    ]
    return coords

def create_slab(x_list: list[float], y_list: list[float], distance):
    coords = create_polygon_coords(x_list, y_list, distance)
    param = {
        "slabsData": [
            {
                "level": 0,
                "polygonCoordinates": coords,
            }
        ]
    }
    run_tapir_command("CreateSlabs", param)

slab_distance = 5
create_slabs(x_list, y_list, slab_distance)


まずはスラブの頂点リストを作成する関数を作成します。
今回はxとy座標のリストからできるバウンディングボックスを指定した距離分オフセットしたものを作成します。

次に柱同様、スラブデータのフォーマットを作成する関数を作成します。
そして、呼び出し側でオフセット距離と座標をcreate_slab関数に渡します。

では、次にスラブの部分をくりぬいたメッシュを作ってみましょう。

def create_mesh(x_list: list[float], y_list: list[float], mesh_distance, hole_distance):
    mesh_coords = create_polygon_coords(x_list, y_list, mesh_distance)
    hole_coords = create_polygon_coords(x_list, y_list, hole_distance)
    param = {
        "meshesData": [
            {
                "level": 0,
                "skirtType": "SurfaceOnlyWithoutSkirt",
                "polygonCoordinates": mesh_coords,
                "holes": [{"polygonCoordinates": hole_coords}],
            }
        ]
    }
    run_tapir_command("CreateMeshes", param)

mesh_distance = 10
create_mesh(x_list, y_list, mesh_distance, slab_distance)

メッシュに穴をあけるので、メッシュ作成の関数は穴の頂点リストも必要です。
スラブの範囲に穴をあけるので、スラブと同じ距離を穴に指定します。

これでメッシュが作成できました。
3Dで見ると画像のような感じになります。

以上で、Tapirを使ったモデリングができました。
現状では梁を作成するコマンドなどがないため、これでモデリング自動化ツールを作ることができるかというとできません。ただ、うまく使っていけばできることも増えるでしょう。

最後までお読みいただきありがとうございました。
以下に、コード全文を載せておきます。

from archicad import ACConnection

conn = ACConnection.connect()
acc = conn.commands
act = conn.types


def run_tapir_command(command: str, param: dict = None) -> dict:
    addOnCommandId = act.AddOnCommandId("TapirCommand", command)
    result = acc.ExecuteAddOnCommand(addOnCommandId, param)
    return result


def create_columns(x_list: list[float], y_list: list[float]) -> None:
    positions = []
    for x in x_list:
        for y in y_list:
            position = {
                "coordinates": {
                    "x": x,
                    "y": y,
                    "z": 0,
                }
            }
            positions.append(position)

    param = {"columnsData": positions}
    run_tapir_command("CreateColumns", param)


def create_polygon_coords(
    x_list: list[float], y_list: list[float], distance
) -> list[dict]:
    min_x = min(x_list) - distance
    max_x = max(x_list) + distance
    min_y = min(y_list) - distance
    max_y = max(y_list) + distance

    coords = [
        {"x": min_x, "y": min_y},
        {"x": max_x, "y": min_y},
        {"x": max_x, "y": max_y},
        {"x": min_x, "y": max_y},
    ]
    return coords


def create_slab(x_list: list[float], y_list: list[float], distance):
    coords = create_polygon_coords(x_list, y_list, distance)
    param = {
        "slabsData": [
            {
                "level": 0,
                "polygonCoordinates": coords,
            }
        ]
    }
    run_tapir_command("CreateSlabs", param)


def create_mesh(x_list: list[float], y_list: list[float], mesh_distance, hole_distance):
    mesh_coords = create_polygon_coords(x_list, y_list, mesh_distance)
    hole_coords = create_polygon_coords(x_list, y_list, hole_distance)
    param = {
        "meshesData": [
            {
                "level": 0,
                "skirtType": "SurfaceOnlyWithoutSkirt",
                "polygonCoordinates": mesh_coords,
                "holes": [{"polygonCoordinates": hole_coords}],
            }
        ]
    }
    run_tapir_command("CreateMeshes", param)


def main():
    x_list = [i * 6 for i in range(10)]
    y_list = [i * 4.5 for i in range(5)]

    create_columns(x_list, y_list)

    slab_distance = 5
    create_slab(x_list, y_list, slab_distance)

    mesh_distance = 10
    create_mesh(x_list, y_list, mesh_distance, slab_distance)


if __name__ == "__main__":
    main()