前回、OpenSCADの公式ユーザーマニュアルを、
噛砕き翻訳したものを覚書程度に殴り書きました。
今回もその続きをやります。
ショック・・・
衝撃的な事実が。公式なのか有志なのか、翻訳されたwikiがありました。
ところどころ無い?内容が違う?程度はありますが(もしかしたら翻訳されたバージョンが最新ではないということなのかな?)しかし最低限は翻訳されている様子です。
というわけで今回の記事がほぼ無駄になってしまった気もしますが、せっかくなのであと少しでもある、Chapter1をやりきりたいと思います。
Chapter1以降は各action()やoperator()などの詳細っぽいので、CheetSheetに触れながら自分がわかりやすいように軽くまとめて終わりになりそうです(要望がありましたら何かしらそれに沿った記事を書きたいと思います)。
では前回の途中から。
基本文法
変数
名前 = 値;
宣言はなく、上記のように決めた名前と=と値とセミコロン(;)で構成される。
OpenSCADの変数は、C言語のような手続き型プログラミング言語だと定数と同じ挙動をするものの、重要な違いがあり、変数に値が複数回割り当てられる場合、最後に割り当てられた値「のみ」がコードの全ての場所で使われる。
変数は、ランタイム時にセットされるのではなく、コンパイル時にセットされる。
これは、コマンドラインで「-D variable=value」オプションを提供する必要があるためである。(コマンドラインオプションの実現を現在ソースコードの最後に配置することで達成しているため)
直観に反するようだが、オーバーライド可能な定数と考えると役に立つ場合がある。
(2015.03以降のバージョンのお話)
変数を任意のスコープで割り当てることができる。
スコープ内で定義した割り当ては、その中でのみ有効。
スコープはoperator()などによってグループ化する際に使う中括弧({})が必要。
スコープ内で定義された値はスコープの外では認識されない。
以下公式にあったサンプルを、手続き型プログラミング言語では異例だと感じる部分をシンプルにまとめてみました。
a = 6;
translate([5,0,0]){
a = 10;
b = 16;
echo(a, b); //100, 16
color("blue"){
echo(a, b); //100, 20
b = 20;
}
echo(a, b); //100, 16
a = 100;
}
echo(a, b); // 6, undef
echoのあとにコメントアウトされている部分は出力内容です。上から順番にechoの返す値についての軽い解説を記述すると、
- 一番上のechoのaは、上から三番目のechoの下のaの値
- 二番目のechoのaは、上から三番目のechoの下のaの値(スコープが上がる前のスコープの最後の値を持っているということ)
- 三番目のechoのbは、一番上のechoの上のbの値(colorスコープのbの値は外に漏れないということ)
という感じだと思います。関数型プログラミングだとこうなるのかな?変数を加減などで反復して使いまわしたりしないあたりの概念が理解できるとOpenSCADの美しさがわかるようになるみたいです。
以上翻訳再開。
operator()などを利用しない、つまり匿名での中括弧を使ってもスコープとはみなされない。
For()文は例外ではなく、コピーしてそれぞれのパスを作っている。
それぞれのパスは、一つのそれぞれスコープをもっており、一意の値を持つことをそのパスによって許されている。
未割り当ての変数は特別な値であるundefを持つ。
途中でもお話しましたが、OpenSCADの変数は関数型プログラミング言語を知らないので多少不自然な挙動に見えますね。ただ、そういうものだと慣れて使用していくだけではありますが。
ベクトル
ベクトルは0個以上のOpenSCADの値を持つシークエンス。
ベクトルは数値やブーリアン値や変数やベクトル自身や文字列やそれらの組み合わせのコレクション(他言語での配列やテーブルと同義)。
もしくはこれらを評価する表現に使える。
つまり多くの手続き型プログラミング言語でいう配列の役割を担う。
[]
[1,2,3]
[a,5,b]
[5.643]
["a","b","string"]
[[1,a],[x,y,z,4.5],[10,[11,12],13],"foo"]
ベクトルは角括弧([])で囲われ、要素をカンマ(,)で区切ることで作成される。
変数は値に置き換えられる。
ベクトルの要素は0からn-1までナンバリングされる。
このnとはlen()の引数にベクトルを入れると戻り値で得られる。
要素へのアドレスは次の記述らがある
a = [1, [2, [3, 4]], 5, "str"];
echo(a[0]); //1
echo(a[1][0]); //2
echo(a[1][1]); //[3, 4]
echo(a[2]); //5
b = 0;
echo(a[1][1][b]); //3
echo(a[a[1][b][b]]); //"str"
echo(a[3][0]); //"s"
echo(a[4]); //undef
ベクトルの最初から3つの要素(0,1,2番目)はドット(.)による代替アクセスができる。
a = [1, 2];
echo(a.x); //1
echo(a.y); //2
echo(a.z); //undef
ベクトルは所謂配列の代わりで、とても柔軟な構造を持つようです。自由に使えますが、変な利用すると使い勝手悪くなりそうな形にもなってますね。
ベクトルの演算
concat();
concat()は二つ以上のベクトルの要素を一つのベクトルに合成する。
ネストレベルは変更されない。
v1 = [1,[2,3]];
v2 = [4];
nv = concat(v1, v2);
echo(nv); //[1, [2, 3], 4]
len();
len()はベクトルか文字列の長さを戻り値とする関数。
要素のインデックスは[0]から[length – 1]。
ベクトルの場合指しているネストレベルの要素数を返す。
文字列の場合文字列の文字数を返す。
どちらでもない値はundefを返す。
v = [1, [2, 3]];
echo(len(v)); //2
str = "abcdefg";
echo(len(str)); //7
また、ベクトルのベクトルは行列である。
といった感じでChapter1全般は大まかに理解できる感じになったと思います。細かいニュアンスや仕様、外部ファイルからのインポートあたりを飛ばしてるかな。わからない人はこの記事の最初にも出しました、日本語翻訳済みマニュアルを利用してみては如何でしょうか。
次回は久しぶりにUnityでやりたいことがあったのでそれをやるか、Pythonの勉強を少しし始めたのでPython系の内容か、やっぱりOpenSCADの続きでCheetSheetsをやるかすると思います。
御覧いただきありがとうございました。
次回もまたよろしくお願いします。