E01 C曲線

フラクタル曲線であるC曲線を作図します。「GeoGebra日本」の「GeoGebra実例」ー「C曲線」と対比させながらやっていきますので,ページを開いて比較しながら読むとよいでしょう。

折れ線を描く

点のリストを与えるとそれらを結んだ線分を描く(GeoGebra実例」では「リストを返す」となっている)コマンドは,Cindyscriptでは connect(list) が用意されています。

C曲線の生成アルゴリズム (CPts1) の作成

2点のリストを与えると、その2点を結ぶ線分を底辺とする直角二等辺三角形の頂点を返す関数です。「GeoGebra実例」では「C曲線の再帰を1ステップ進める1点を加えたリストを返すコマンドを作成します。」となっていますが,ここではその点だけを返すことにします。

cpts1(list):=(

z1=complex(list_1);

z2=complex(list_2);

z3=z1+(z2-z1)*1/sqrt(2)*(cos(pi/4)+i*sin(pi/4));

gauss(z3);

);

点A,Bを作図ツールでとり,

draw(cpts1([A,B]);

を実行すると次のようになります。

C曲線の点を生成するツール (CPts) の作成

複数の点のリストを与えると、2つずつをとって cpts1() で新たな点をとり元のリストに追加していく関数です。「GeoGebra実例」では「C曲線の再帰を1ステップ進めたリストを返す」となっています。

たとえば,[A,B,C] を引数に与えると,AB,BCのそれぞれに対して cpts1() で作った点を間に入れていきます。

まず,ABに対して点p1をとり,[A,p1] とします。

次に,BCに対して点p2をとり,[A,p1,B,p2] とします。

最後にCを追加します。あとで,これらを折れ線で結ぶのです。

cpts(list):=(

ret=[];

repeat(length(list)-1,s,

ret=append(ret,list_s);

ret=append(ret,cpts1([list_s,list_(s+1)]));

);

ret=append(ret,list_(-1));

);

C曲線ツール (CCurve) の作成

最後に2点を与えるとC曲線を描画する関数を作成します。cpts() を繰り返し使って点を増やしていき,最後に線を結んで描画します。繰り返しの数も引数で与えることにします。

Ccurve(list,n):=(

plist=list;

repeat(n,plist=cpts(plist));

connect(plist);

);

実行する

関数の定義ができたら,実行します。

Ccurve([A,B],10);

とすると,次の図ができます。GeoGebra実例 と同じ図です。

なお,Ccurve() の中の connect(plist); を次のように変えると,線分で結ばない点だけが表示されます。

forall(pt,draw(#));

第2引数を大きくすればさらに細かくできるのですが,処理量が2のn乗になりますので注意が必要です。処理に要する時間がそれだけ増えるわけです。

次の図は Ccurve([A,B],15); の場合ですが,このくらいまででしょう。20にすると,ほとんどハングアップ状態になって,強制終了しなくてはなりません。

今までに書いた関数定義をまとめて再掲しておきます。ネット上を探すといろいろなプログラミングの例がありますが,ここまで簡単なものはなかなかないでしょう。

// 2点のリストから直角二等辺三角形の頂点を返す

cpts1(list):=(

z1=complex(list_1);

z2=complex(list_2);

z3=z1+(z2-z1)*1/sqrt(2)*(cos(pi/4)+i*sin(pi/4));

gauss(z3);

);

// 複数の点のリストに対し,2点ずつ cpts1()を適用した点を追加したリストを返す。

cpts(list):=(

ret=[];

repeat(length(list)-1,s,

ret=append(ret,list_s);

ret=append(ret,cpts1([list_s,list_(s+1)]));

);

ret=append(ret,list_(-1));

);

// 2点のリストと回数を与えてC曲線を描く nは13くらいまで

Ccurve(list,n):=(

plist=list;

repeat(n,plist=cpts(plist));

connect(plist);

);

Ccurve([A,B],10);

位置を変える

cpts1() では,2点を結ぶ線分を底辺とする直角二等辺三角形の頂点を求めました。この位置を変えるとどうなるでしょう。底角が30°の二等辺三角形の頂点にしてみましょう。3行目のz3の式を変えるだけです。

z3=z1+(z2-z1)/cos(pi/6)/2*(cos(pi/6)+i*sin(pi/6));

この位置になります。 10回やるとこうなります。


さらに回数を増やす:Cinderellaで作図

前述した通り,繰り返し回数を増やすと,処理回数が2のn乗(+1)になり,15回ぐらいが限度です。しかし,Cinderellaに用意されているIFS(反復関数系)の機能を用いるともっと多く反復することができます。

2点を結ぶ線分を底辺とする直角二等辺三角形の頂点を求めるのは,45°の回転と1/√2 倍を組み合わせたもので,これを「相似変換」といいます。

もう一つ増やした図を,直角二等辺三角形の3頂点から出発したと考えると,点AをCの周りに回転して 1/√2 倍したものと,BをCの周りに回転して 1/√2 倍したと考えられます。これを繰り返せば同じ図ができます。

ここから始めて こうなる

ではやってみましょう。はじめに3つの点が必要なので点Cもとっておきます。正確な位置はあとで決めますので,とりあえず,それらしい位置にします。

今,点Cをとったところです。動かすモードにして,画面のどこかをクリックし,Cが選択されていない状態にします。

モードメニューの「変換」から「相似変換」を選びます。ツールバーの下に現れるガイドに従って,まず1つ目のもとになる点としてAをクリックします。次に1つ目の点が写る点としてCをクリックするのですが,矢印でガイドが出るので,A→C となるようにします。

次に2つめですが,今度は,もとになる点も写る点もBにします。

これで相似変換が定義されて,右上にアイコンが出ます。

同様にして,B→C,A→A の相似変換を定義します。

動かすモードに戻り,Shiftクリックで右上の2つのアイコンを選択します。

モードメニューの「特別」から「反復関数系IFS」を選びます。図形ができて,右上には「IFS0」というアイコンができます。

点Cの位置をドラッグすると図形も変わります。

C曲線にするために,点Cの位置をCindyscriptで決めましょう。

z1=complex(A);

z2=complex(B);

C.xy=gauss(z1+(z2-z1)/sqrt(2)*(cos(pi/4)+i*sin(pi/4)));

ところで,「C曲線」の名前の由来ですが,形がアルファベットのCの形をしている,ということなのですね。

A,Bをドラッグして縦に置くとわかります。これだけの複雑な図形でもほとんどリアルタイムに動かすことができます。