IU Tips

ゾーン名に通し番号を一括で付ける方法【Archicad】【Python】

2024.02.01

こんにちは。

IU BIM STUDIOの原田です。

今回はArchicadで作成したモデルのゾーンにPythonを使って一括で通し番号をつけていく方法を紹介したいと思います。

モデルはArchicadのサンプルモデルS造オフィスビルを使います。
後で説明しますが、今回コードを基本から説明するためにモデルは少し修正しています。

モデルの確認

まず、ゾーンがどのようになっているかを確認しましょう。

画像のような配置になっています。

スクリプトの作成

まず、テンプレ部分を書きます

from archicad import ACConnection

conn = ACConnection.connect()
assert conn

acc = conn.commands
act = conn.types
acu = conn.utilities

次に、ゾーンから現在のゾーン名を取得します

# プロパティのGUIDを取得
propertyId = acu.GetBuiltInPropertyId("Zone_ZoneName")

# ゾーンを全て取得
zones = acc.GetElementsByType("Zone")

# ゾーン名を取得
zone_name_properties = acc.GetPropertyValuesOfElements(zones, [propertyId])

# 文字列のみのリストを作成
zone_names = [i.propertyValues[0].propertyValue.value for i in zone_name_properties]

ゾーン名のプロパティIDとゾーンのGUIDを取得してゾーン名のプロパティ値を取得します。
GetPropertyValuesOfElementsのプロパティID引数はリストのみなので、角括弧で囲んでいます。

GetPropertyValuesOfElementsの戻り値は文字列ではなく、PropertyValueクラスのリストのような形で返ってきます。室名を加工したいので文字列のみを取り出したリストを作成します。

そして、室名を変更して新しいプロパティ値を作成するコードを書いていきます。

property_values = []
zone_number_dict = {}

property_valuesは新規に作ったゾーン名を入れておくリスト、
zone_number_dictは通し番号がどこまで進んでいるかを保存しておく辞書です。

for zone, zone_name in zip(zones, zone_names):
    # ゾーン名が1つの場合は番号を付けない
    if zone_names.count(zone_name) <= 1:
        continue

    # 通し番号を更新
    if zone_name in zone_number_dict:
        zone_number_dict[zone_name] += 1
    else:
        zone_number_dict[zone_name] = 1

    # ゾーン名の文字列を作成
    zone_number = zone_number_dict[zone_name]
    new_zone_name = act.NormalStringPropertyValue(f"{zone_name}_{zone_number}")

    # 変更内容のリストを作成
    property_value = act.ElementPropertyValue(zone.elementId, propertyId, new_zone_name)
    property_values.append(property_value)

for文でループし、一部屋ずつ処理していきます。

今回はゾーン名が1つしかないものには番号を付けないため、室名がリスト内に1つしかない場合はcontinueで飛ばします。

ゾーン名を処理するごとに辞書のキーに室名がある場合は通し番号をプラス1し、ない場合は1とするように辞書を更新します。

辞書の更新作業が終わったら、室名と通し番号を連結した文字列を作成し、その文字列からプロパティ値型のオブジェクトを作成しリストに追加していきます。

最後にプロパティ値を更新して完成です。

# 作成した変更をゾーンに適用
acc.SetPropertyValuesOfElements(property_values)

これで1つしかない室には通し番号なし、複数ある室には通し番号を振るという作業が一瞬で完了しました。

現状の問題点

ただし、最初に書いたように実際はここまできれいにはいきませんでした。

何かといいますと最初に取得したときのゾーンの順番というのが必ずしも下の階からというわけではなく、番号が階によって散らばりきれいな順番に採番されませんでした。

テストしたモデルではゾーンを一回消してコピペしていますので、もしかしたら配置した順番なのかもしれません。

また、このあたりを解決する方法を考えてみたいと思います。

Pythonを利用して単純な作業は自動化しましょう!!

今回は以上です。

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

from archicad import ACConnection

conn = ACConnection.connect()
assert conn

acc = conn.commands
act = conn.types
acu = conn.utilities

# プロパティのGUIDを取得
propertyId = acu.GetBuiltInPropertyId("Zone_ZoneName")

# ゾーンを全て取得
zones = acc.GetElementsByType("Zone")

# ゾーン名を取得
zone_name_properties = acc.GetPropertyValuesOfElements(zones, [propertyId])

# 文字列のみのリストを作成
zone_names = [i.propertyValues[0].propertyValue.value for i in zone_name_properties]


property_values = []
zone_number_dict = {}

for zone, zone_name in zip(zones, zone_names):
    # ゾーン名が1つの場合は枝番を付けない
    if zone_names.count(zone_name) <= 1:
        continue

    # 通し番号を更新
    if zone_name in zone_number_dict:
        zone_number_dict[zone_name] += 1
    else:
        zone_number_dict[zone_name] = 1

    # ゾーン名の文字列を作成
    zone_number = zone_number_dict[zone_name]
    new_zone_name = act.NormalStringPropertyValue(f"{zone_name}_{zone_number}")

    # 変更内容のリストを作成
    property_value = act.ElementPropertyValue(zone.elementId, propertyId, new_zone_name)
    property_values.append(property_value)

# 作成した変更をゾーンに適用
acc.SetPropertyValuesOfElements(property_values)