ドラゴン曲線を描画する話。
まず、ドラゴン曲線とは次のようなもの。
ドラゴン曲線
左下の端っこが途切れているところからスタートして、方向を変化させながら進んでいく感じ(canvas2Dでの描画なので回転方向が時計回り、まあどっちでもいいんだけど)。
とりあえずオリジナルの定義。
があらわすベクトルの方向に点が進むことを表現する。このときたとえば、
という配列は、右、上、左、上という順番で進むことをあらわす。つまり
方向列
すなわち前半を元の方向列に対し
ドラゴン曲線2
フラクタル図形としてのドラゴン曲線はこうじゃないけど、すべてのセグメントが同じ長さとしたときのものを考えているのでこんな感じになる。
この定義だとどんどん長くしていくのが困難で規則も見出しづらいので、スタートが
すなわち後半は逆配列にして
これを
となるがここで
なので方向が真逆になる。これを
のようになっている。これは一般的に成り立つ。なぜならどの段階においても
このことを用いると、項数を使うことでどの方向に曲がるのかを計算できる。第
これを繰り返すといずれ
初期方向を
例えば
なので
こうなるともう
自分はよくp5.jsという描画ライブラリを使うので、それによる描画コードを載せる:
let a = 0;
let b = 0;
let f = 0;
function setup(){
createCanvas(640, 640);
background(0);
stroke(255);
}
function draw(){
translate(320, 320);
let dir = f & 1;
let h = 1;
while(f >= h){
if(!(f & h) && (f & (h * 2))){ dir += 2; }
h *= 2;
}
let s = 8 * cos(dir * PI / 2);
let t = 8 * sin(dir * PI / 2);
line(a, b, a + s, b + t);
a += s;
b += t;
f++;
}
作品のリンク
描画結果:
ドラゴン曲線3
中央上の切れたところからスタートしている。点
短く書くとこんな感じ:
w=640;a=b=f=k=0;c=320
setup=()=>{createCanvas(w,w);background(0);k=PI/2}
draw=()=>{translate(c,c);e=f&1;h=1;while(f>=h){if(!(f&h)&&(f&(h*2))){e+=2}h*=2}s=8*cos(k*e);t=8*sin(k*e);stroke(w);line(a,b,a+=s,b+=t);f++}
これは実は
w=640;a=b=f=k=0;c=320
setup=()=>{createCanvas(w,w);background(0);k=PI/2}
draw=()=>{translate(c,c);e=f&1;h=1;while(f>=h){if(!(f&h)&&(f&(h*2))){e+=2}h*=2}s=8*cos(k*e);t=8*sin(k*e);r=4;while(r--){rotate(k);stroke(r*90,(r&1)*w,w);line(a,b,a+s,b+t)}a+=s;b+=t;f++}
作品のリンク
実行結果:
ドラゴン曲線4
すなわちすべての隣接格子点間のセグメントを
let w = 640;
let a = 320;
let b = 320;
let f = 0;
function setup(){
createCanvas(w, w);
colorMode(HSB, 64);
}
function draw(){
let e = (f & 1) * 2 - 1;
let h = 1;
while (f >= h) {
if (!(f & h) && (f & (h * 2))) {
e += 4;
}
h *= 2;
}
let s = 9 * cos(PI * e / 4);
let t = 9 * sin(PI * e / 4);
let r = 5;
while (--r) {
applyMatrix(0, -1, 1, 0, 0, w);
fill(r * 12, w, w);
quad(a, b, a, b + t, a + s, b + t, a + s, b);
}
a += s;
b += t;
f++;
}
ドラゴン曲線6
曲線を描くだけなら最終的にこのくらい短く書ける(p5js)。
a=b=180;f=0;draw=_=>{k=PI/2;if(!f){createCanvas(640,640)}e=f&1;h=1;while(f>=h){if(!(f&h)&&(f&(h*2))){e+=2}h*=2}line(a,b,a-=8*cos(k*e),b+=8*sin(k*e));f++}
差分に着目したらもっと短くなった。
x=y=180;u=8;v=f=0;draw=_=>{if(!f){createCanvas(640,640)}line(x,y,x-=u,y+=v);s=++f;while(1-s%2){s/=2}k=1-(s&2);z=u;u=-k*v;v=k*z}