「武器を身につけよう」へ戻る

sub、functionプロシージャー

ちょっと大きめのスクリプトを作ると、どこに何があるか判らないようなスクリプトになってしまうことがあります。
また、同じような処理を何回も記述していることに気が付くことがあります。
このようなときに便利なのがプロシージャー(sub,function)です。

Subプロシージャー


まずは下図でイメージを頭に浮かべてください。
Topへ
図のようにプロシージャーは加工機械のようなものです。
原料を与えて製品を作るように、変数を引数として与え処理を行わせるブラックボックスのようなものです。
一度作ってしまえば後で何度でも同じ処理を行えます。
この場合、引数は加工機械の設定値のようなものでもあります。
これを変更することにより違った製品(結果)を作ることができるのです。
スクリプトではこのようなブラックボックスを別の場所にまとめて記述しておき,必要なときに呼び出すということになります。
イメージとしては左図のような感じです。

さっそくShade上での例題を見てみましょう


次のスクリプトは
選択した線形状のPtNo番目のアンカーポイントをx軸方向にdx,Y軸方向にdy,z軸方向にdz動かす
という処理をsub形式(ブラックボックス)にまとめたものです。

とりあえず、左図のように4つのアンカーポイントからなる適当な開いた線形状を作り、線形状を選択し、下のスクリプトを実行して挙動を確認してください。
'-----スクリプト本体(スクリプトレベル)
'PtNo:動かすのは何番目のアンカーポイントか。
'x:x軸方向に動かす量(mm)
'y:y軸方向に動かす量(mm)
'z:z軸方向に動かす量(mm)
dim PtNo,x,y,z			'point0 スクリプトレベルの変数宣言
PtNo=1
x=10
y=20
z=30
call MovePoint(PtNo,x,y,z)	'point1 subの呼び出し。callはなくても良い
xshade.message(x&" "&y&" "&z)	'point2 変数内容の確認用

'(加工機械の設定を変えるように)変数の値を変えてもう一度subを利用する。
PtNo=2
x=100
y=200
z=300
call MovePoint(PtNo,x,y,z)  'point3 subの呼び出し。callはなくても良い。

'-----subプロシージャーです。(プロシージャーレベル) point4
sub MovePoint(PointNo,dx,dy,dz)
  dim x,y,z			'point5 プロシージャレベルの変数宣言
  x=XShade.AnchorPoint(PointNo,0)
  y=XShade.AnchorPoint(PointNo,1)
  z=XShade.AnchorPoint(PointNo,2)
  XShade.AnchorPoint(PointNo,0)=x+dx
  XShade.AnchorPoint(PointNo,1)=y+dy
  XShade.AnchorPoint(PointNo,2)=z+dz
end sub
Topへ
上は簡単なsubプロシージャーの例です。
まず、形から見ていきましょう。
subプロシージャ自体(point4以降)は

sub 名前(引数1,引数2,・・)
で始まり
end sub
で終わります。

名前は呼び出すときに必要です。
引数とはイメージ図で説明したように原料のようなもので、subプロシージャ内での処理に必要な変数です。
引数をdimで宣言していないことにも中止してください。(代わりに呼び出し側で対応する変数を宣言しています。)
この引数は呼び出すときに指定(上記の例では[point 1,point3]の部分)されます。
上記の例でもわかるように複数の引数があるときはカンマで区切ります。
呼び出し側の形は

call sub名(引数1,引数2,・・)

またはcallを省略して

sub名 引数1,引数2,・・

のようにもできます。但しこの場合は引数の括弧も省略するのも忘れないで下さい。

また、変数名は呼び出し側とsub側で同じである必要はなく、順番が重要になります。
例の場合を言葉でいうと
「PtNoをPointNo,xをdx,yをdy,zをdzに置き換えた上でsub MovePointからend subまでの処理を行う」
ということになります。(正確な表現ではありませんが)

スコープ(変数の適用範囲)

上記の例でもう一つ注目してもらいたいのは変数の名前です。
最初(point0)のdimx,y,zを宣言し、subプロシージャーの中(point5)でもdimx,y,zを宣言しています。
同じ変数でもsubプロシージャー内で宣言した変数はプロシージャー内でのみ有効になります。
言い換えるとプロシージャー内(point5)で宣言したx,y,zの値を変更してもスクリプトレベル(point0)で宣言したx,y,zには影響がないということです。
別の変数と思ってもらって結構です。
point2で変数の中身をメッセージウィンドウに表示させたのは
「プロシージャー内で宣言されたx,y,zの内容を変更しても、呼び出し側のスクリプトのx,y,zの値が変わっていないこと」を確認してもらう為に記述したものです。
実際に実行して確認してみてください。
これは意外に大切なことです。
もし、subプロシージャーを使わずにcallのところにsubプロシージャ内の処理をいちいち記述することを考えると別の変数名を使わなくてはいけなくなるからです。
このようにスクリプト本体と独立させることで変数名など余分なことに気を使う必要がなくなり、プロシージャーの処理だけに集中してスクリプトを書くことができます。

一つの例題について簡単に説明してきましたが、subプロシージャーを使うことの利点は何でしょう。

・同じ処理を何度も記述する必要がない。
・長いスクリプトをプロシージャーに部品化することでデバッグ(エラーを直す)しやすくなる。
・見やすくなる。
・変更が一ヶ所で済む。
・よく使う処理などは部品化することで他のスクリプトにもコピー・アンド・ペーストで流用できる。
・(スクリプトレベルの)変数の混乱(競合)が起こりにくい
などがあります。



Functionプロシージャー

subプロシージャーとほとんど同じですが戻り値を持つ点だけが異なります。
それではshade上で例題を見てみましょう。

次のスクリプトは
PtNo1番目のアンカーポイントとPtNo2番目のアンカーポイントとの距離を計算して表示する
という処理をfunction形式(ブラックボックス)にまとめたものです。

とりあえず、4つのアンカーポイントからなる適当な開いた線形状を作り、線形状を選択し、下のスクリプトを実行して挙動を確認してください。(左図)

結果はメッセージウィンドウに下図のように表示されるはずです。

Topへ
dim PtNo1,PtNo2,PtDistance
PtNo1=0
PtNo2=1
PtDistance=PointsDist(PtNo1,PtNo2)	'point1
XShade.Message(PtNo1&"番目のポイントと"PtNo2&"番目のポイントの距離は"&PtDistance&"(mm)です。"
PtNo1=0
PtNo2=2
PtDistance=PointsDist(PtNo1,PtNo2)	'point2
XShade.Message(PtNo1&"番目のポイントと"PtNo2&"番目のポイントの距離は"&PtDistance&"(mm)です。"

function PointsDist(PointNo1,PointNo2)
'j=0:x座標値  j=1:y座標値  j=2:z座標値を意味する。
'pos1は取り出した最初のアンカーポイントの各座標値を一時的に保管する為の変数
'pos2は取り出した二番目ののアンカーポイントの各座標値を一時的に保管する為の変数
'Deltaは最初と二番目のポイントのx,y,zそれぞれの差を保管する配列(距離の計算に必要)
  dim j,pos1,pos2,Delta(2)
  for j=0 to 2
    pos1=XShade.AnchorPoint(PointNo1,j)
    pos2=XShade.AnchorPoint(PointNo2,j)
    Delta(j)=pos2-pos1
  next
'point3 距離の計算結果をfunctionの名前と同じ変数に代入
    PointsDist=(Delta(0)^2+Delta(1)^2+Delta(2)^2)^(1/2)
end function
まず、形から見ていきましょう。
functionプロシージャ自体は

function 名前(引数1,引数2,・・)
で始まり、処理の結果を
名前=・・・
のようにfunctionの名前と同じ変数(宣言する必要はない)に代入し
end function
で終わります。
名前は呼び出すときに(代入式で)必要です。
引数とは以前イメージ図で説明したように原料のようなもので、Functionプロシージャ内での処理に必要な変数です。
引数をdimで宣言していないことにも中止してください。(変わりに呼び出し側で対応する変数を宣言しています。)
この引数はsubプロシージャー同様呼び出すときに指定されます。
上記の例でもわかるように複数の引数があるときはカンマで区切ります。
呼び出し側の形は

変数=functionの名前(引数1,引数2,・・)
(上記の例では PtDistance=PointsDist(PtNo1,PtNo2)の部分 )

となります。
つまりプロシージャー自体が(結果の)値を持っている(これを戻り値という)ので、それを別の変数に代入する形をとります。
数学で
y=f(x)
というのがありますがあれと同じ感覚です。
point1〜point3の違いだけ気をつければ後はsubプロシージャーとほとんど同じです。

以上プロシージャ(sub,function)について概略(不十分ですが)を説明してみました。
refvalについても説明したかったのですが煩雑になるので省略します。
詳細についてはMicrosoftのホームページにあるマニュアルを参照してください。
「武器を身につけよう」へ戻る Topへ