2

テルドラゴン曲線を描く

69
0

テルドラゴン曲線というのがある。次のように作る。

テルドラゴン曲線

方向列を[0]からスタートして次のように作っていく。
[a0,a1,,an1][a0,a1,,an1,a0+1,a1+1,,an1+1,a0,a1,,an1]
成分は0,1,2でモジュロ3の足し算とする。ひとつひとつは120°回転に対応している。このやり方で作っていく曲線のことをいう。こんな感じ:
テルドラゴン1 テルドラゴン1
回転方向は時計回りとする。
[0][0,1,0][0,1,0,1,2,1,0,1,0]

作っていくとこんな感じになる。
テルドラゴン2 テルドラゴン2
この曲線のn回目の進行方向を考えてみる(0回目は0, 1回目は1,)。まず、方向列の作り方が、
[α][α, α+1, α]
となっている。この3つの区分はn3進数展開したときの最上位桁0,1,2に対応しているので、それが1の場合だけ真ん中に入る。そして1を引いて続きはαの中で同じことをする。それは頭の桁を取り去ることに対応するから、結局桁が1のときだけ実際の値から1を引いて残りを調べる形になる。最後は[0,1,0]だから末尾も1のときだけ1になってて最後は0になる。ゆえに、1の数だけ120°回転すればnでの進行方向が出る。

テルドラゴン曲線の進行方向

テルドラゴン曲線の第n番目の進行方向は、n3進数展開したときに桁に現れる1の個数だけ120°回転した方向。

最初のいくつかの数字を3進数展開して並べてみる:
0, 1, 2, 10, 11, 12, 20, 21, 22, 100, 101, 102, 110, 111, 112, 120, 121, 
確かに1の個数で回転角が決まっていることが分かる。
 実際にこれをp5.jsで作成するコードを置いておく。 作品ページ

      let a = 0;
let b = 0;
let f = 0;

function setup(){
    createCanvas(600, 600);
    stroke(255);
    background(0);
}

function draw(){
    translate(540, 300);
    let u = f;
    let x = 0;
    while(u){
        x += (u % 3) & 1;
        u = (u - (u % 3)) / 3;
    }
    let c = 20 * cos(x * 2 * PI / 3);
    let s = 20 * sin(x * 2 * PI / 3);
    line(a, b, a + c, b + s);
    a += c;
    b += s;
    f++;
}
    

fが項数で、uに代入して計算しているところで使っている。x1の個数。下から見ていく。0,1,2のうち&を取って1になるのは1だけだからビット演算で出る。1の個数に2π/3を掛けると進行方向が出る。そんな感じ。

6つの方向に出してみる

テルドラゴン曲線は6つの方向に伸ばしていくと正三角形格子のすべての辺を一つ残らずなぞることが知られている。それを実行したコードがこれ:
作品ページ
テルドラゴン3 テルドラゴン3

      let a = 0;
let b = 0;
let f = 0;
function setup(){
    createCanvas(600, 600);
    colorMode(HSB, 100);
    background(0);
}

function draw(){
    translate(300, 300);
    let u = f;
    let x = 0;
    while(u){
        x += (u % 3) & 1;
        u = (u - (u % 3)) / 3;
    }
    let c = 9 * cos(x * 2 * PI / 3);
    let s = 9 * sin(x * 2 * PI / 3);
    let r = 6;
    while(r--){
        rotate(PI / 3);
        let v = r % 2;
        stroke(55, 100 * v, 100);
        line(a, b, a + c, b + s);
    }
    a += c;
    b += s;
    f++;
}
    

すべての辺をちょうど1回ずつ通るので、そこにひし形を配置して平面充填することができる。それを実行するとこんな感じになる:
作品ページ
テルドラゴン4 テルドラゴン4

      const SIZE = 640;
const HALF_SIZE = SIZE / 2;
let x = 0;
let y = 0;
let properFrameCount = 0;
const k = Math.PI / 3;
const UNIT_LENGTH = 6;
const SHORT_LENGTH = UNIT_LENGTH / Math.sqrt(3);

let gr;

function setup(){
    createCanvas(SIZE, SIZE);
    gr = createGraphics(SIZE, SIZE);
    gr.colorMode(HSB, 96);
    gr.noStroke();
    gr.translate(HALF_SIZE, HALF_SIZE);
}

function draw(){
    background(128);
    let rp = 20;
    while(rp--){
        let u = properFrameCount;
        let z = 0;
        while(u){
            z += 2 * ((u % 3) & 1);
            u = (u - (u % 3)) / 3;
        }
        let s = UNIT_LENGTH * cos(z * k);
        let t = UNIT_LENGTH * sin(z * k);
        let s1 = SHORT_LENGTH * cos(z * k - PI / 6);
        let t1 = SHORT_LENGTH * sin(z * k - PI / 6);
        let s2 = SHORT_LENGTH * cos(z * k + PI / 6);
        let t2 = SHORT_LENGTH * sin(z * k + PI / 6);
        let r = 6;
        const sat = properFrameCount % 50 + 50;
        const blt = properFrameCount % 40 + 60;
        while(r--){
            gr.rotate(k);
            gr.fill(r * 16, sat, blt);
            gr.quad(x, y, x + s1, y + t1, x + s, y + t, x + s2, y + t2);
        }
        x += s;
        y += t;
        properFrameCount++;
    }
    image(gr, 0, 0);
    if(properFrameCount > 14000){ noLoop(); }
}
    

すべての格子の辺を1回ずつ通るのについてはそのうち証明してみたいと思う。ドラゴン曲線の方も(正方形格子)。あっちはなんとか証明できそうなのでそのうち上げたい。

投稿日:20201128
OptHub AI Competition

この記事を高評価した人

高評価したユーザはいません

この記事に送られたバッジ

バッジはありません。
バッチを贈って投稿者を応援しよう

バッチを贈ると投稿者に現金やAmazonのギフトカードが還元されます。

投稿者

黒狐
黒狐
34
4950
数学ちょっと好きです!

コメント

他の人のコメント

コメントはありません。
読み込み中...
読み込み中