前回はスクリプトを使ってワークシートを作成する方法を解説しました。今回はその続きとして、ワークシートのセルやデータベース行の「中身」をスクリプトで生成する方法を解説します。
※今回の記事はDeveloperサイトで解説されているWorksheet Scriptingと同じ内容になります。
ワークシートはVectorworksの図面からあらゆるデータを集計できる強力な機能ですが、ときには通常のワークシート関数だけでは解決できない場面に出会うことがあります。そのような場合、セルや行の値をスクリプトで計算して書き戻すことで、ワークシートで複雑な計算やデータを扱うことができるようになります。
スクリプトは強力な反面、Vectorworksのデータモデルへの深い理解が必要になります。また、ワークシートにスクリプトを組み込むと複雑さが増し、ワークシートの再計算の負荷に影響することがある点にも注意が必要です。
スクリプトが必要になるケースとしては、次のようなものがあります。
-
- データがそのままでは取得できず、計算する必要がある場合
- 列の集計や合計を行った後に、その値をもとに計算する必要がある場合
74-1. ワークシートスクリプト
ワークシートスクリプトには、大きく分けて2つの使い方があります。
-
- セルの中身を生成するスクリプト:RunScript 関数および RunScriptEdit 関数を使用します。
- データベース行の行データを生成するスクリプト:DatabaseByScript 関数を使用します。
スクリプトは現在のドキュメントのリソースブラウザの中に置くことができ、その場合はリソースの名前で参照します。Vectorworksはリソースマネージャ内のどのフォルダに置かれていても、名前さえ一致すればスクリプトを見つけてくれます。
=RunScript('MyScript')
# 現在のドキュメント内にある「MyScript」という名前のスクリプトを実行する
# フォルダ構成に関わらず検索される
または、Vectorworksのフォルダ構成の中にあるスクリプトファイルを実行することもできます。
=RunScript(120, 'Landmark Schedules/SaveLandscapeAreaBeforePlants.py') # 第1引数は標準フォルダの識別子 # 第2引数はスクリプトファイルへの相対パス
74-2. ワークシートとスクリプトの連動の考え方
基本的な考え方は、「Vectorworksがスクリプトを実行し、パラメータを渡し、スクリプトがセルの値や行データとして使われるデータを出力する」というものです。
ワークシート関数に追加で渡したパラメータは、そのままスクリプトに引き渡されます。これを利用すると、状況に応じて異なる動作をする多機能なスクリプトを作ることができます。
74-3. セルの値を生成するスクリプト
スクリプトは、他の関数と並べてセルの数式の中で使うことができます。RunScript 関数は数式の中で実行し、値を返すために使います
RunScriptEdit 関数はセルに対して単独の関数として使い、セルの値を取得するためにスクリプトを実行するだけでなく、ユーザーがセルの値を変更したときにも実行され、その値をワークシートへ書き戻すことができます。
これらはデータベース行のセルを含む、あらゆるセルで使用できます。データベース行で使った場合、その行が表すオブジェクトごとに、スクリプトが独立して実行されます。
74-3-1. RunScript
次のような数式をセルに設定したとします。
=RunScript('MyScript', 1, 2, 'hello')
# 現在のドキュメント内の「MyScript」を実行する(フォルダ構成に関わらず検索)
# スクリプトにパラメータを渡す
セルの値が計算されるたびに、RunScript 関数はスクリプト(現在のファイル内、または外部のものを実行できます)を実行し、パラメータをスクリプトに引き渡します。データベース行であれば、その行に対応するオブジェクトのハンドルも一緒に渡されます。
次はスクリプトの例です。ポイントは、スクリプトが「入力を読み取り」「何かを計算し」「1つの出力を返す」という流れになっていることです。
h = vs.WSScript_GetObject()
prm0 = vs.WSScript_GetPrmInt(0)
prm1 = vs.WSScript_GetPrmReal(1)
prm2 = vs.WSScript_GetPrmStr(2)
result = f"{prm2}: {prm0}:{prm1} of {repr(h)}"
vs.WSScript_SetResStr(result)
このスクリプトは、入力パラメータを読み取り、結果を生成し、それをセルへ返します。
入力の取得
スクリプトの入力にアクセスするための関数です。パラメータの型に応じて、正しい関数を呼び出す必要がある点に注意してください。
| WSScript_GetObject() -> HANDLE | この行のオブジェクトのハンドルを返します。データベース行のセルで実行された場合のみ有効です。 |
| WSScript_GetPrmInt(paramIndex) -> INTEGER | 指定したインデックスのパラメータを整数値として返します。 |
| WSScript_GetPrmReal(paramIndex) -> REAL | 指定したインデックスのパラメータを実数値として返します。 |
| WSScript_GetPrmStr(paramIndex) -> STRING | 指定したインデックスのパラメータを文字列値として返します。 |
出力の設定
スクリプトの出力を設定するための関数です。これらのうち1つだけを、スクリプトの最後で使用してください。どの関数を使うかによって、セルの値の型が決まります。
| WSScript_SetResStr(value) | 文字列値を返します。 |
| WSScript_SetResReal(value) | 実数値を返します。 |
| WSScript_SetResInt(value) | 整数値を返します。 |
| WSScript_SetResImage(handle) | セルに表示する画像のハンドルを返します。このハンドルは図面内にすでに存在している必要があり、通常はこの行のオブジェクト(ハンドル)、つまり処理中のオブジェクト内にある画像のハンドルになります。 |
74-3-2. RunScriptEdit
次のような数式をセルに設定したとします。
=RunScriptEdit('MyScript', 1, 2, 'hello')
# 現在のドキュメント内の「MyScript」を実行する(フォルダ構成に関わらず検索)
# スクリプトにパラメータを渡す
この関数を使うと、セルを編集可能にできます。スクリプト自体はほぼ同じですが、セルの値が変更されたときにも実行される点が異なります。WSScript_GetEdit() -> isEdit, newValue を使うと、スクリプトがなぜ実行されているのか(値の読み取りなのか、編集なのか)を確認できます。
prm0 = vs.WSScript_GetPrmInt(0)
prm1 = vs.WSScript_GetPrmReal(1)
prm2 = vs.WSScript_GetPrmStr(2)
# スクリプトが実行された理由を確認する
# セルが編集されている場合は、その新しい値を取得する
isEdit, newValue = vs.WSScript_GetEdit()
if not isEdit:
# セルの値を決定するために情報を読み取っている
h = vs.WSScript_GetObject()
result = f"{prm2}: {prm0}:{prm1} of {repr(h)}"
vs.WSScript_SetResStr(result)
else:
# セルが編集されている
# このセルの下にある可能性のあるすべてのオブジェクトをループする
# 列がサマライズされている場合は1つの行に対して複数のオブジェクト/ハンドルが存在するため、
# ここではそれらをすべて列挙して新しい値を書き込む
# このスクリプト内でセルの値を決定する際に、新しい値を反映する必要があるため重要
i = 0
while True:
ok, h = vs.WSScript_GetEditObj( i )
if not ok:
break;
vs.AlrtDialog( f"change the value of object {repr(h)} to '{newValue}'" )
i += 1
# 編集が正常に完了したことを示す
# 0を返すと失敗を意味し、セルの値は元に戻される
# 1を返すと、新しいセルの値を決定するためにこのスクリプトが再度実行される
# 注意:この例は実際のデータを読み書きしていないため、常に元の値に戻る
# (読み取りが常に固定値を返すため)
vs.WSScript_SetResInt( 1 )
※この例は、読み取りが常に同じ値を返すため実際には動作しません。OKが返されても、書き込みは実質的に何もしていません。あくまで処理の流れを示すための例としてご覧ください。
74-4. データベース行を生成するスクリプト
このスクリプトの用途は、検索条件式だけではデータベース行のサブ行を決められない場合です。通常、行を右クリックして「データベース」にすると、オブジェクトを一覧するための検索条件を指定します。一覧された各オブジェクトが、それぞれサブ行になります。このスクリプトを使うと、サブ行を表すハンドルのリストを手動で指定することができます。
この数式はデータベース行で使用する必要があります。手順は次のとおりです。
-
- 行を右クリックし、「データベース」メニューコマンドを実行する
- ダイアログでそのままOKをクリックする
- 同じ行をもう一度右クリックし、「データベース計算式の編集」メニューコマンドを実行する
- これで、数式バーで行の数式を指定できるようになります
=DataBaseByScript('MyRowsScript', 1, 2, 'hello')
# 現在のドキュメント内の「MyRowsScript」を実行する(フォルダ構成に関わらず検索)
# スクリプトにパラメータを渡す
考え方は同様ですが、今回はスクリプトが次の関数を使ってデータベース行に表示するオブジェクトのハンドルのリストを取得します。
| WSScript_AddHandle(handle) | 行となるハンドルを1つ提供します。 |
| WSScript_AddHandleId(handle, id) | IDを付けて行のハンドルを提供します。これにより、ソート時に同じIDの行同士がまとまって並ぶようになります。 |
prm0 = vs.WSScript_GetPrmInt(0)
prm1 = vs.WSScript_GetPrmReal(1)
prm2 = vs.WSScript_GetPrmStr(2)
arrObject = []
def collectAllObj(h):
arrObject.append(h)
vs.ForEachObject(collectAllObj, "(L='Design Layer-1')")
for h in arrObject:
vs.WSScript_AddHandle(h)
このスクリプトは、コールバックを使って検索条件でオブジェクトを一覧し、それらを集めて返しています。Vectorworksはオブジェクトごとにデータベース行を作成します。ここで提供したハンドルは、通常の検索条件で生成された場合と同じように、この行のすべてのセル関数で使われます。この例自体は通常の検索条件と大きく変わりませんが、ロジックでリストを制御できるようになる点がポイントです。
74-5. 役立つコードスニペット集
ここからは、実際の活用例として役立つコードスニペットを紹介します。
植栽オブジェクトに植栽スタイルの画像を表示する
# セルの数式
#
# 植栽スペースの植栽オブジェクトを受け取り
# 植栽スペースオブジェクトから植栽の画像を取り出す
#
# 例: =RUNSCRIPT('MyScript')
#
imgObj = vs.Handle()
h = vs.WSScript_GetObject()
if h != vs.Handle():
# この植栽に関連付けられたシンボルの名前を取得する
objName = vs.GetRField( h, 'Plant Record', 'Plantlist Name' )
hDef = vs.GetObject( objName )
if hDef != vs.Handle():
# スタイルシンボルから、パラメトリックを画像としてセルに提供する
if hDef.type == 16:
imgObj = hDef.first
else:
imgObj = hDef
vs.WSScript_SetResImage( imgObj )
植栽を一覧する
# データベース行の数式
#
# 植栽スペース用のローカルPythonスクリプトを実行し、植栽より先に植栽スペースを保存する。
# 既定の順序では植栽が先に、その後に植栽スペースが保存される。
# このスクリプトでは植栽スペースを先に、植栽を後に保存する。
# その結果、ワークシート上では植栽スペースがその中の植栽より先に並ぶ。
#
# 例: =DATABASEBYSCRIPT('MyRowsScript')
# 例: =DATABASEBYSCRIPT('MyRowsScript', 1) # 仕切り(divider)も一覧する
#
arrObject = []
def collectAllObj(h):
arrObject.append(h)
def check_h_is_la(h):
if ( vs.GetObjectVariableInt(h, 1165) == 191):
return True
else:
return False
# パラメータに応じて、仕切り(divider)レコードを一覧するかどうかを切り替える
listDividers = vs.WSScript_GetPrmInt(0)
if listDividers:
vs.ForEachObject(collectAllObj, "(((R IN ['Landscape Area']) | (R IN ['Plant Record']) | (R IN ['Divider Record'])) & (NOT (R IN ['Plant'])))")
else:
vs.ForEachObject(collectAllObj, "(((R IN ['Landscape Area']) | (R IN ['Plant Record'])) & (NOT (R IN ['Plant'])))")
arrPlants = []
id = 1
# 見つかったオブジェクトを順に処理し、植栽スペースを先に、続いてその植栽を報告する
# 同じ植栽スペース内の植栽にはすべて同じIDを付けることで、まとまってソートされる
# (異なる植栽スペース間で植栽が混ざらないようにする)
for h in arrObject:
if check_h_is_la(h):
vs.WSScript_AddHandleId(h, id)
for plant in arrPlants:
vs.WSScript_AddHandleId(plant, id)
arrPlants.clear()
id += 1
else:
arrPlants.append(h)
植栽スペースから情報を取り出す
この情報は複雑な形式で保存されているため、デコードするためのスクリプトが必要になります。
なお、これはあくまで実演のための例です。Vectorworksには、この用途に便利な関数がすでに用意されています。
# セルの数式
#
# 植栽スペースの植栽オブジェクトを受け取り
# 植栽スペースオブジェクトからその植栽の割合(パーセンテージ)を取り出す
#
# 例: =RUNSCRIPTEDIT('MyScript')
#
isEdit, newValue = vs.WSScript_GetEdit()
if isEdit == False:
h = vs.WSScript_GetObject()
strResult = ''
hParent = h.parent
if h != vs.Handle():
# オブジェクトから割合の配列を取得する
strRate = vs.GetRField( hParent, 'Landscape Area', 'hiddenPercentage' )
# 日本語環境のMacでは、ワークシート内で実行したときに '\n' が
# strRate の区切り文字と一致しないことがあるため、明示的に指定する
arrRate = strRate.split(bytes([10]).decode())
strResult = ''
# どの割合が現在のデータに対応するかをループで探す
i = 0
hCurrent = hParent.first
while hCurrent != vs.Handle() and i < len(arrRate):
if hCurrent.type == 2:
if h == hCurrent:
strResult = arrRate[ i ]
break
i += 1
hCurrent = hCurrent.next
vs.WSScript_SetResStr( strResult )
elif int(newValue) >= 0 and int(newValue) <= 100: # 入力値を検証する
iObj = 0
while True:
ok, h = vs.WSScript_GetEditObj( iObj )
if not ok:
break;
if vs.SetLAField( h, 0, newValue ):
vs.WSScript_SetResInt( 1 ) # 新しい値を確定する
iObj += 1
通常のワークシート関数では難しい集計や、図面のデータモデルに踏み込んだ処理が必要になったときは、ぜひ今回紹介したワークシートスクリプティングを活用してみてください。
この機能を利用できる製品
|
Vectorworks Fundamentals2D/3D汎用作図機能に、プレゼンボード作成機能や図面と連動できる表計算機能など、数多くの基本作図機能に加え、高品質レンダリング&3Dビジュアライズ機能を搭載したVectorworksシリーズの基本製品 |
|
Vectorworks Architect建築設計や内装、ディスプレイデザインに対応した先進的なBIM・インテリア設計支援機能、拡張機能、さらには豊富な建築向けのデータライブラリを搭載した建築/内装業界向け製品 |
|
Vectorworks Landmark地形モデルや多彩な植栽、灌水設備計画等に対応するランドスケープデザイン機能、さらには豊富な造園向けのデータライブラリを搭載した都市計画/造園業界向け製品 |
|
Vectorworks Spotlightステージプランニングやライティング計画に対応した先進的な舞台照明計画支援機能、さらには各種メーカー製のトラスや照明機材、音響機器等の豊富なデータライブラリを搭載したエンタテインメント業界向け製品 |
|
Vectorworks Design Suite専門分野別(建築設計/ディスプレイデザイン、ランドスケープデザイン、ステージデザイン&スポットライトプランニング)の設計支援機能、拡張機能、さらには豊富なデータライブラリを搭載した最上位の製品 |






