アポロニアのガスケットを描く


28

3つの相互に接する円が与えられた場合、それら3つすべてに接する2つの円を常に見つけることができます。これら2つはアポロニア円と呼ばれます。アポロニアの円の1つが実際に3つの初期円の周りにあることに注意してください。

3つの接線円から始めて、次のプロセスでアポロニアンガスケットと呼ばれるフラクタルを作成できます。

  1. 最初の3つの円を親の円と呼びます
  2. 親円の2つのアポロニア円を見つける
  3. 各アポロニア円について:
    1. 親円の3つのペアの各ペアに対して:
      1. アポロニアン円と2つの親円を新しい親円のセットと呼び、ステップ2からやり直します。

たとえば、同じサイズの円から始めて、次のようになります。

ここに画像の説明を入力してください

ウィキペディアで見つかった画像

必要な表記法がもう1つあります。中心(x、y)の半径rの円がある場合、その曲率をk =±1 / rとして定義できます。通常、kは正ですが、負のkを使用して、ガスケット内の他のすべての円を囲む円を示します(つまり、すべての接線が内側からその円に接触します)。次に、3組の数字で円を指定できます:(k、x * k、y * k)

この質問の目的のために、正の整数kと有理xおよびyを仮定します。

このようなサークルのその他の例は、Wikipediaの記事に記載れています

また、この記事には、一体型ガスケットに関する興味深いものがあります(他の面白い点もあります)。

チャレンジ

4つの円の指定が与えられ、それぞれがのようになります(14, 28/35, -112/105)eval必要に応じて単純に入力できるように、便利なリスト形式と除算演算子を使用できます。4つの円は実際に互いに接しており、最初の円は負の曲率を持っていると仮定できます。これは、他の3つのアポロニア円が既に与えられていることを意味します。有効な入力例のリストについては、チャレンジの下部をご覧ください。

この入力が与えられると、アポロニアンガスケットを描画するプログラムまたは関数を記述します。

関数引数、ARGVまたはSTDINを介して入力を取得し、画面上にフラクタルをレンダリングするか、選択した形式で画像ファイルに書き込むことができます。

結果の画像をラスタライズする場合、各円は少なくとも400ピクセルで、最大の円の周りに20%未満のパディングが必要です。半径が最大入力円の400未満の円、またはピクセルより小さい円のいずれか早い方に到達すると、再帰を停止できます。

完全なディスクではなく、円の輪郭のみを描画する必要がありますが、背景と線の色は任意です。アウトラインは、外側の円の直径の200倍より広くしてはなりません。

これはコードゴルフなので、最短の回答(バイト単位)が勝ちです。

入力例

Wikipediaの記事のすべての不可欠なガスケットは、所定の入力形式に変換されています。

[[-1, 0, 0], [2, 1, 0], [2, -1, 0], [3, 0, 2]]
[[-2, 0, 0], [3, 1/2, 0], [6, -2, 0], [7, -3/2, 2]]
[[-3, 0, 0], [4, 1/3, 0], [12, -3, 0], [13, -8/3, 2]]
[[-3, 0, 0], [5, 2/3, 0], [8, -4/3, -1], [8, -4/3, 1]]
[[-4, 0, 0], [5, 1/4, 0], [20, -4, 0], [21, -15/4, 2]]
[[-4, 0, 0], [8, 1, 0], [9, -3/4, -1], [9, -3/4, 1]]
[[-5, 0, 0], [6, 1/5, 0], [30, -5, 0], [31, -24/5, 2]]
[[-5, 0, 0], [7, 2/5, 0], [18, -12/5, -1], [18, -12/5, 1]]
[[-6, 0, 0], [7, 1/6, 0], [42, -6, 0], [43, -35/6, 2]]
[[-6, 0, 0], [10, 2/3, 0], [15, -3/2, 0], [19, -5/6, 2]]
[[-6, 0, 0], [11, 5/6, 0], [14, -16/15, -4/5], [15, -9/10, 6/5]]
[[-7, 0, 0], [8, 1/7, 0], [56, -7, 0], [57, -48/7, 2]]
[[-7, 0, 0], [9, 2/7, 0], [32, -24/7, -1], [32, -24/7, 1]]
[[-7, 0, 0], [12, 5/7, 0], [17, -48/35, -2/5], [20, -33/35, 8/5]]
[[-8, 0, 0], [9, 1/8, 0], [72, -8, 0], [73, -63/8, 2]]
[[-8, 0, 0], [12, 1/2, 0], [25, -15/8, -1], [25, -15/8, 1]]
[[-8, 0, 0], [13, 5/8, 0], [21, -63/40, -2/5], [24, -6/5, 8/5]]
[[-9, 0, 0], [10, 1/9, 0], [90, -9, 0], [91, -80/9, 2]]
[[-9, 0, 0], [11, 2/9, 0], [50, -40/9, -1], [50, -40/9, 1]]
[[-9, 0, 0], [14, 5/9, 0], [26, -77/45, -4/5], [27, -8/5, 6/5]]
[[-9, 0, 0], [18, 1, 0], [19, -8/9, -2/3], [22, -5/9, 4/3]]
[[-10, 0, 0], [11, 1/10, 0], [110, -10, 0], [111, -99/10, 2]]
[[-10, 0, 0], [14, 2/5, 0], [35, -5/2, 0], [39, -21/10, 2]]
[[-10, 0, 0], [18, 4/5, 0], [23, -6/5, -1/2], [27, -4/5, 3/2]]
[[-11, 0, 0], [12, 1/11, 0], [132, -11, 0], [133, -120/11, 2]]
[[-11, 0, 0], [13, 2/11, 0], [72, -60/11, -1], [72, -60/11, 1]]
[[-11, 0, 0], [16, 5/11, 0], [36, -117/55, -4/5], [37, -112/55, 6/5]]
[[-11, 0, 0], [21, 10/11, 0], [24, -56/55, -3/5], [28, -36/55, 7/5]]
[[-12, 0, 0], [13, 1/12, 0], [156, -12, 0], [157, -143/12, 2]]
[[-12, 0, 0], [16, 1/3, 0], [49, -35/12, -1], [49, -35/12, 1]]
[[-12, 0, 0], [17, 5/12, 0], [41, -143/60, -2/5], [44, -32/15, 8/5]]
[[-12, 0, 0], [21, 3/4, 0], [28, -4/3, 0], [37, -7/12, 2]]
[[-12, 0, 0], [21, 3/4, 0], [29, -5/4, -2/3], [32, -1, 4/3]]
[[-12, 0, 0], [25, 13/12, 0], [25, -119/156, -10/13], [28, -20/39, 16/13]]
[[-13, 0, 0], [14, 1/13, 0], [182, -13, 0], [183, -168/13, 2]]
[[-13, 0, 0], [15, 2/13, 0], [98, -84/13, -1], [98, -84/13, 1]]
[[-13, 0, 0], [18, 5/13, 0], [47, -168/65, -2/5], [50, -153/65, 8/5]]
[[-13, 0, 0], [23, 10/13, 0], [30, -84/65, -1/5], [38, -44/65, 9/5]]
[[-14, 0, 0], [15, 1/14, 0], [210, -14, 0], [211, -195/14, 2]]
[[-14, 0, 0], [18, 2/7, 0], [63, -7/2, 0], [67, -45/14, 2]]
[[-14, 0, 0], [19, 5/14, 0], [54, -96/35, -4/5], [55, -187/70, 6/5]]
[[-14, 0, 0], [22, 4/7, 0], [39, -12/7, -1/2], [43, -10/7, 3/2]]
[[-14, 0, 0], [27, 13/14, 0], [31, -171/182, -10/13], [34, -66/91, 16/13]]
[[-15, 0, 0], [16, 1/15, 0], [240, -15, 0], [241, -224/15, 2]]
[[-15, 0, 0], [17, 2/15, 0], [128, -112/15, -1], [128, -112/15, 1]]
[[-15, 0, 0], [24, 3/5, 0], [40, -5/3, 0], [49, -16/15, 2]]
[[-15, 0, 0], [24, 3/5, 0], [41, -8/5, -2/3], [44, -7/5, 4/3]]
[[-15, 0, 0], [28, 13/15, 0], [33, -72/65, -6/13], [40, -25/39, 20/13]]
[[-15, 0, 0], [32, 17/15, 0], [32, -161/255, -16/17], [33, -48/85, 18/17]]

あなたのイラストの例は、最初の操作の後、「内側」のアポロニア円のみを含んでいるようです。
スパー14年

@Sparrどういう意味かわかりません。最初の操作の後、2つのアポロニア円の1つが既に存在し(現在の反復で選択しなかった元の親円)、他の解だけを探しています。
マーティンエンダー14年

気にしないで、あなたは正しい、私は誤読していた。
スパー14年

回答:


12

GolfScript(ベクトル289バイト/ラスター237バイト)

289バイトで、妥当な時間内に実行:

'/'/n*','/']['*0,`1/*~1.$[]*(~-400*:&;{1+1=*}/:D;{{1+2<~D@*\/}%}%'<svg><g fill="none" stroke="red">'puts.{[[~@:b[D&*\abs]{@&*[b]+}2*]{'.0/'*'"#{
}"'n/*~}%'<circle r="
" cx="
" cy="
" />'n/\]zip puts}:|/[{.([.;]+}3*]{(:?zip{)\~++2*\-}%:c.|0=D&*<{?);[c]+[{([.;]+.}3*;]+}*.}do'</g></svg>'

これは、stdinの入力を受け取り、stdoutへのSVGファイルを生成します。残念ながら、オンラインデモには少し時間がかかりますが、早期に中止される微調整されたバージョンはあなたにアイデアを与えることができます。

入力[[-2, 0, 0], [3, 1/2, 0], [6, -2, 0], [7, -3/2, 2]]が与えられると(InkScapeでPNGに変換された)出力

ガスケット2/3/6/7


237バイトで、非常に長い時間がかかります(1ビットの白黒ではありますが、上記と同様の出力を生成するのに1週間以上かかると推測しています)。

'/'/n*','/']['*0,`1/*~1.$[]*(~-400*:&;{1+1=*}/:D;{{1+2<~D@*\/}%}%.[{.([.;]+}3*]{(:?[zip{)\~++2*\-}%:c]@+\0c=D&*<{?);[c]+[{([.;]+.}3*;]+}*.}do;:C;'P1 ''801 '2*.~:B*,{:P;C{:?[0=2/.D&*-.*\D&*+.*]{2,{P{B/}2$*B%400-?0=*\)?=&*-.*}/+<},,1=},!}/

出力は改行のないNetPBM形式であるため、GIMPがまだロードしますが、仕様に厳密に従っていない可能性があります。厳密な適合が必要な場合はn、最後の後にを挿入し!ます。

ラスタライズは、各円に対して各ピクセルをテストすることにより行われるため、かかる時間は、ピクセル数と円の数の関係でほぼ線形です。すべてを10分の1に縮小することにより、

'/'/n*','/']['*0,`1/*~1.$[]*(~-40*:&;{1+1=*}/:D;{{1+2<~D@*\/}%}%.[{.([.;]+}3*]{(:?[zip{)\~++2*\-}%:c]@+\0c=D&*<{?);[c]+[{([.;]+.}3*;]+}*.}do;:C;'P1 ''81 '2*.~:B*,{:P;C{:?[0=2/.D&*-.*\D&*+.*]{2,{P{B/}2$*B%40-?0=*\)?=&*-.*}/+<},,1=},!}/

10分で実行し、生成します

81x81画像

(GIMPでPNGに変換)。36時間を与えられて401x401を作り出した

401x401画像


3
Golfscriptでグラフィカルな出力ができるとは思いもしませんでした
ベータ崩壊

12

JavaScript(418410バイト)

関数として実装:

function A(s){P='<svg><g fill=none stroke=red transform=translate(400,400)>';Q=[];s=eval(s);S=-400*s[0][0];function d(c){P+='<circle r='+Math.abs(p=S/c[0])+' cx='+p*c[1]+' cy='+p*c[2]+' />'}for(c=4;c--;d(s[0]),s.push(s.shift()))Q.push(s.slice());for(;s=Q.shift();d(c)){c=[];for(i=4;i--;)c[i]=2*(s[0][i]+s[1][i]+s[2][i])-s[3][i];for(i=6;c[0]<S&&i;)Q.push([s[i--%3],s[i--%3],c,s[i%3]])}document.body.innerHTML=P}

オンラインデモ(注:暗黙的なサイジングに関するSVG仕様の要件を満たさないブラウザーでは動作しないため、このバグを回避するために少し長いバージョンを提供します。 Inkscapeは属性の引用に関して少し厳密ですが)。

を使用すると8バイトを節約できますがdocument.write、それはjsFiddleに深刻な影響を与えることに注意してください。


1
おそらく、例えば、ES6で関数を定義し、保存することにより、より節約することができますS/c[0]変数にし、その後も取り除くMath.absなど三項演算子で
インゴ・バーク

@IngoBürk、ES6ルートに行く場合は、代わりにCoffeeScriptで記述します。
ピーターテイラー14年

ホストc99.nlを使用します。document.writeを許可します。
xem 14年

2
これに対する答えを見るのは良いことです:)
MickyT 14年

@IngoBürkの一時変数の提案で更新されました。排除Math.absすることは実際にキャラクターにコストがかかります。
ピーターテイラー14年

6

Mathematica 289文字

双線形システムを解くことにより http://arxiv.org/pdf/math/0101066v1.pdf Theorem 2.2(非常に非効率的)。

不要なスペース、まだゴルフ中:

w = {k, x, y};
d = IdentityMatrix;
j = Join;
p_~f~h_ := If[#[[-1, 1]] < 6! h,
    q = 2 d@4 - 1;
    m = #~j~{w};
    r = Complement[w /. NSolve[ And @@ j @@ 
                        MapThread[Equal, {Thread@m.q.m, 4 d@3 {0, 1, 1}}, 2], w], a];
    If[r != {},
     a~AppendTo~# & @@ r;
     Function[x, x~j~{#}~f~h & /@ r]@#]] & /@ p~Subsets~{3}; 
Graphics[Circle @@@ ({{##2}, 1}/# & @@@ (f[a = #, -Tr@#]; a))] &

入力付きの縮小されたサイズのアニメーション {{-13, 0, 0}, {23, 10/13, 0}, {30, -84/65, -1/5}, {38, -44/65, 9/5}}

ここに画像の説明を入力してください


どのように入力しますか?
マーティンエンダー

@MartinBüttner、関数の引数として@{{-1, 0, 0}, {2, 1, 0}, {2, -1, 0}, {3, 0, 2}}、最後の行に追加することにより
ベリサリウス博士

@MartinBüttnerテストする場合は、の50/h代わりに最初に試してください400/h。より速く結果を得ることができます。また、次のように入力して進行状況を監視することができますDynamic@Length@a機能を実行する前に
博士ベリサリウス

Instructions for testing this answer (with a reduced number of circles) without Mathematica installed:1)pastebinからこれをダウンロードし、*。CDFとして保存します。2)Wolfram Researchから無料のCDF環境をダウンロードし、インストールます(小さなファイルではありません)。楽しい。動作するかどうか教えてください!-注:計算が遅いため、グラフィックが表示されるまで待ちます。
ベリサリウス博士14年

「非常に非効率的な」コメントとは何ですか?(アニメーションを見て)あなたは明らかにほとんどの円を少なくとも2回描いているのでしょうか?複雑なデカルトのアプローチは、本質的に効率が高いと思います。
ピーターテイラー14年

4

メープル(960バイト)

デカルトの定理を使用してアポロニアンガスケットを生成し、Mapleのプロットシステムを使用してプロットしました。時間があれば、これをさらにゴルフしたいし、Pythonに変更したい(Mapleは間違いなくフラクタルに最適ではありません)。私のコードを実行したい場合、無料のMapleプレーヤーへのリンクを次に示します。

X,Y,Z,S,N:=abs,evalf,member,sqrt,numelems;
f:=proc(J)
    L:=map((x)->[x[1],(x[2]+x[3]*I)/x[1]+50*(1+I)/X(J[1][2])],J);
    R:=Vector([L]);
    T,r:=X(L[1][3]),L[1][4];
    A(L[1][5],L[2][6],L[3][7],L[1][8],L[2][9],L[3][10],R,T,r);
    A(L[1][11],L[2][12],L[4][13],L[1][14],L[2][15],L[4][16],R,T,r);
    A(L[1][17],L[3][18],L[4][19],L[1][20],L[3][21],L[4][22],R,T,r);
    A(L[2][23],L[3][24],L[4][25],L[2][26],L[3][27],L[4][28],R,T,r);
    plots[display](seq(plottools[circle]([Re(R[i][29]),Im(R[i][30])],X(1/R[i][31])),i=1..N(R))):
end proc:
A:=proc(a,b,c,i,j,k,R,E,F)
    K:=i+k+j+2*S(i*k+i*j+k*j);
    if K>400*E then
    return;
    end if;
    C:=(a*i+c*k+b*j+2*S(a*c*i*k+b*c*j*k+a*b*i*j))/K;
    C2:=(a*i+c*k+b*j-2*S(a*c*i*k+b*c*j*k+a*b*i*j))/K;
    if Y(X(C-F))<1/E and not Z([K,C],R) then
    R(N(R)+1):=[K,C];
    A(a,b,C,i,j,K,R,E,F);
    A(a,c,C,i,k,K,R,E,F);
    A(b,c,C,j,k,K,R,E,F);
    end if:    
    if Y(X(C2-F))<1/E and not Z([K,C2],R) then
    R(N(R)+1):=[K,C2];
    A(a,b,C2,i,j,K,R,E,F);
    A(a,c,C2,i,k,K,R,E,F);
    A(b,c,C2,j,k,K,R,E,F);
    end if: 
end proc:

一部のサンプルガスケット

f([[-1, 0, 0], [2, 1, 0], [2, -1, 0], [3, 0, 2]]);

ここに画像の説明を入力してください

f([[-9, 0, 0], [14, 5/9, 0], [26, -77/45, -4/5], [27, -8/5, 6/5]]);

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.