IU Tips

Archicadでステップ図を作成する

2025.12.17

こんにちは。IU BIM STUDIOの原田です。
今回はArchicadでステップ図を作るためのアイディアを紹介したいと思います。

Archicadでステップ図を作成するときに段階ごとにレイヤーを分けて、ステップごとにレイヤーセットを作成し、ビューで作る方法をよく見かけます。
これはモデラーにとって表示の切り替えを作成しやすい一方で、施工ステップの情報を正しく管理しているとは言えません。なぜなら、レイヤーとは施工手順の情報ではなくArchicadでの表示非表示の情報だからです。

今回はプロパティを作成し、TapirとPythonを使ってステップを可視化する方法について紹介します。

今回、Tapirに独自のコマンドを追加しますが、そちらの説明については省略します。

プロパティの作成

ステップ図の段階を入力するためにプロパティを作成します。仮設要素も入力したい場合を考えて、開始と終了を作成しておきます。

この時、少し考えないといけないことがあります。

モデル内の要素すべてを表示するわけではないケースもあるでしょうから、そのための設定を考える必要があります。今回は「ステップ図に表示」というプロパティをTrue/False型で作成します

また、モデル要素が常設要素かどうか判定をする必要があります。終了プロパティが0の場合常設要素とするというような方法もできなくはないですが、1つのプロパティに複数の意味(ステップの番号と常設かどうかの判定)を持たせるとプログラムの処理が煩雑になり、今後の拡張性にも影響します。なので、今回は常設要素というプロパティをTrue/False型で作ります。

これを踏まえて、モデルにステップの番号を入力します。

モデルの作成

というわけで、サンプルモデルを作成しました。

柱と梁、敷地は常設要素、トラックは仮設要素です。樹木はステップ図では非表示とします。ステップの順番は適当です。

常設要素である柱・梁にはそれぞれの開始ステップを入力し、終了は0になっています。

仮設要素であるトラックは開始・終了に値を入力し、常設要素はFalseにしておきます。

非表示要素である樹木はステップ図に表示をFalseにしておきます。

Pythonスクリプトの作成

今回はGUIからスライダーでステップを表示するようにしたいと思います。下記のようなウィンドウを作成します。

機能としては、スライダーをドラッグすると一つ一つ次のステップを表示します。ただ、ステップ数が多いと操作しづらくなると思われるので、数値指定でも見れるようにしておきます。

ライブラリ等の準備

まず、使用するライブラリ等のインポートをします。Archicad Python APIのいつものやつも書いておきます

import tkinter as tk
from tkinter import messagebox

import pandas as pd
from archicad import ACConnection

conn: ACConnection = ACConnection.connect()
acc = conn.commands
act = conn.types
acu = conn.utilities


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

ウィンドウの作成

今回はPythonデフォルトGUIライブラリのTKinterを使います。作成するウィンドウのクラスを作成していきます。

class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        master.geometry("250x150")
        master.title("ステップ表示")

        self.min_value = tk.IntVar()
        self.max_value = tk.IntVar()

        self.get_step_values()
        self.create_widget()

        self.show_elements_by_step(self.min_value.get())


def main():
    win = tk.Tk()
    app = Application(master=win)
    app.mainloop()


if __name__ == "__main__":
    main()

今回、スライダーの最小値、最大値をウィンドウの変数として扱いたいためこれらを作成しておきます。tk.IntVarはTKinterで使う整数型の変数です。
関数に関しては後で説明しますが、ステップの値を取得、ウィジェットを作成、ステップの最初の段階を初期状態として表示という流れになっています。

Archiadのプロパティを取得する

まず、Archicadのステップ関係のプロパティを取得します。モデルが大きい場合など、ステップを変えるごとに毎回Archicadからプロパティを取得するのは遅いと思われるので、今回は起動時にpandasのデータフレームを作成しておき、ステップに合致する要素のGUIDを取得するというようにしておきます。

    def get_step_values(self):
        property_ids = []
        property_ids.append(
            acu.GetUserDefinedPropertyId("ステップ", "ステップ図に表示")
        )
        property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "常設要素"))
        property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "開始"))
        property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "終了"))

        elements = acc.GetAllElements()

        property_values_of_elements = acc.GetPropertyValuesOfElements(
            elements, property_ids
        )

        data = []

        for element, properties in zip(elements, property_values_of_elements):
            match properties.propertyValues[0].propertyValue.status:
                case "normal":
                    show_in_step_view = properties.propertyValues[0].propertyValue.value
                    if not show_in_step_view:
                        continue

                    guid = str(element.elementId.guid)
                    is_permanent = properties.propertyValues[1].propertyValue.value
                    start = properties.propertyValues[2].propertyValue.value
                    end = properties.propertyValues[3].propertyValue.value

                    data.append([guid, start, end, is_permanent])
                case "notAvailable":
                    continue
                case _:
                    raise ValueError

        self.df = pd.DataFrame(data, columns=["GUID", "開始", "終了", "常設要素"])
        min_value = int(self.df["開始"].min())
        max_value = int(self.df["開始"].max())
        self.min_value.set(min_value)
        self.max_value.set(max_value)

まず、必要なプロパティIDを取得し、全てのモデル要素を取得、その後プロパティの値を取得します。

取得したプロパティ値をループし、それぞれを処理していきます。全てのモデル要素を取得しているため、ステップの対象外の要素は除外する必要があります。

まずはmatch文を使って、そもそもプロパティの対象外になっている要素を除外します。ステータスがnotAvailableのものがプロパティ割り当ての対象外のものになります。サンプルでは特に問題はありませんでしたが、想定外の要素が来たとき分かるようにValueErrorが出るようにしています。

そして、ステータスがnormalの時に値を取得します。ただ、ステップ図で表示しないもの、つまりshow_in_step_viewがFalseのものは非表示なので除外します。

ステップの表示対象であればリストにGUID、開始、終了、常設要素の値を追加していきます。

リストが作成し終わったら、データフレームを作成し、開始プロパティの最小値と最大値をtk.IntVarの変数にセットしておきます。

ウィジェットを作成する

次に、GUIにウィジェットを配置していきます。

    def create_widget(self):
        label = tk.Label(self.master, text="表示ステップ")
        label.place(x=10, y=10)

        self.scale = tk.Scale(
            self.master,
            from_=self.min_value.get(),
            to=self.max_value.get(),
            orient="horizontal",
            width=15,
            length=200,
            command=self.show_elements_by_step,
        )
        self.scale.place(x=10, y=40)

        label = tk.Label(self.master, text="ステップ設定")
        label.place(x=10, y=100)

        self.entry = tk.Entry(self.master, width=5)
        self.entry.insert(0, 1)
        self.entry.place(x=100, y=100)

        button = tk.Button(text="設定", command=self.set_step_value)
        button.place(x=170, y=97)

ウィジェットは5つです。

ラベルはテキストを表示させるものです。特に説明はいらないかと思います。

ステップを移動させるスライダーですが、TKinterではScaleと呼ぶようです。from_とtoに先ほど取得した開始の最小値と最大値を入力します。commandはスライダーを動かしたときに呼ぶ関数です。この関数で指定した要素のみを表示します。

Entryは一般に言うテキストボックスのことです。テキストボックスは初期値として1を入れて配置しておきます。

Buttonは名前の通りボタンです。クリックしたときにスライダーに数値をセットする関数を呼びます。

以上でウィジェットの配置は終わりです。

ステップの数値指定入力

ステップをテキストボックスから数値指定で入力するための関数を作成します。

    def set_step_value(self):
        value = self.entry.get()
        try:
            int_value = int(value)
        except ValueError:
            messagebox.showwarning("注意", "数字を入力してください")
            return

        self.scale.set(int_value)

テキストボックスの値を取得してスケールにセットします。

ただ、テキストボックスには数値以外も入力できてしまうので、数値以外の時には警告が出るようにしておきます。

指定した要素の表示

スライダーを操作すると、指定したステップの要素だけが表示されるようにします

    def show_elements_by_step(self, val):
        x = int(val)

        guids = self.df.query("開始 <= @x and (@x <= 終了 or 常設要素 == True)")["GUID"]
        guids_json = [{"elementId": {"guid": i}} for i in guids.to_list()]
        param = {"elements": guids_json}
        run_tapir_command("ShowSelectedElement", param)

valはスライダーから受け取るステップの値です。受け取った時点では文字列型なので、整数に変換します。

次に、受け取ったステップで表示する要素のGUIDを抽出します。データフレームのqueryメソッドで条件を指定します。条件は

・ステップが開始の値より後 
 かつ
・ステップが終了の値より前 又は 常設要素がTrue

となるものを表示します。

GUIDが抽出できたらJSON形式にして、tapirのコマンドを呼びます。

冒頭にも書いたように、この記事ではtapir側のコードは省略しますが、tapirのコマンド追加さえできればそこまで難しくないと思います。

動作確認

では、実際に動かしてみましょう。

仮設要素込みのステップで要素を表示できました。

まとめ

以上で、プロパティを利用してステップ図を作成することができました。

モデルのデータは情報の用途をよく考え、データを整理して入力することで威力を発揮します。

レイヤーでステップ図を作成した場合、それはレイヤーを切り替える用途にしか使えない(使いにくい)のですが、ステップ用のプロパティをきちんと作ることで、情報を他にも活用することができます。

次回はステップのプロパティをそのまま利用して工程表(ガントチャート)を作っていきます。

最後までお読みいただきありがとうございました。

以下にコード全文を載せておきます。

import tkinter as tk
from tkinter import messagebox

import pandas as pd
from archicad import ACConnection

conn: ACConnection = ACConnection.connect()
acc = conn.commands
act = conn.types
acu = conn.utilities


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


class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        master.geometry("250x150")
        master.title("ステップ表示")

        self.min_value = tk.IntVar()
        self.max_value = tk.IntVar()
        self.get_step_values()
        self.create_widget()

        self.show_elements_by_step(self.min_value.get())

    def create_widget(self):
        label = tk.Label(self.master, text="表示ステップ")
        label.place(x=10, y=10)

        self.scale = tk.Scale(
            self.master,
            from_=self.min_value.get(),
            to=self.max_value.get(),
            orient="horizontal",
            width=15,
            length=200,
            command=self.show_elements_by_step,
        )
        self.scale.place(x=10, y=40)

        label = tk.Label(self.master, text="ステップ設定")
        label.place(x=10, y=100)

        self.entry = tk.Entry(self.master, width=5)
        self.entry.insert(0, 1)
        self.entry.place(x=100, y=100)

        button = tk.Button(text="設定", command=self.set_step_value)
        button.place(x=170, y=97)

    def get_step_values(self):
        property_ids = []
        property_ids.append(
            acu.GetUserDefinedPropertyId("ステップ", "ステップ図に表示")
        )
        property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "常設要素"))
        property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "開始"))
        property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "終了"))

        elements = acc.GetAllElements()

        property_values_of_elements = acc.GetPropertyValuesOfElements(
            elements, property_ids
        )

        data = []

        for element, properties in zip(elements, property_values_of_elements):
            match properties.propertyValues[0].propertyValue.status:
                case "normal":
                    show_in_step_view = properties.propertyValues[0].propertyValue.value
                    if not show_in_step_view:
                        continue

                    guid = str(element.elementId.guid)
                    is_permanent = properties.propertyValues[1].propertyValue.value
                    start = properties.propertyValues[2].propertyValue.value
                    end = properties.propertyValues[3].propertyValue.value

                    data.append([guid, start, end, is_permanent])
                case "notAvailable":
                    continue
                case _:
                    raise ValueError

        self.df = pd.DataFrame(data, columns=["GUID", "開始", "終了", "常設要素"])
        min_value = int(self.df["開始"].min())
        max_value = int(self.df["開始"].max())
        self.min_value.set(min_value)
        self.max_value.set(max_value)

    def set_step_value(self):
        value = self.entry.get()
        try:
            int_value = int(value)
        except ValueError:
            messagebox.showwarning("注意", "数字を入力してください")
            return

        self.scale.set(int_value)

    def show_elements_by_step(self, val):
        x = int(val)

        guids = self.df.query("開始 <= @x and (@x <= 終了 or 常設要素 == True)")["GUID"]
        guids_json = [{"elementId": {"guid": i}} for i in guids.to_list()]
        param = {"elements": guids_json}
        run_tapir_command("ShowSelectedElement", param) #要コマンド追加


def main():
    win = tk.Tk()
    app = Application(master=win)
    app.mainloop()


if __name__ == "__main__":
    main()