아폴로니아 개스킷 그리기


28

서로 접하는 원이 3 개인 경우 항상 3 개의 접하는 원을 찾을 수 있습니다 . 이 두 가지는 아폴로니아 원 이라고 합니다 . 아폴로니아 원 중 하나는 실제로 세 개의 초기 원 주위에 있을 수 있습니다 .

3 개의 접선에서 시작 하여 다음 프로세스를 통해 Apollonian gasket 이라는 프랙탈을 만들 수 있습니다 .

  1. 처음 3 개의 서클을 상위 서클이라고합니다.
  2. 부모 서클의 두 아폴로니아 서클 찾기
  3. 각 아폴로니아 원의 경우 :
    1. 부모 쌍 세 쌍의 각 쌍에 대해 :
      1. 아폴로니아 원과 두 부모 원을 새로운 부모 원으로 부르고 2 단계부터 다시 시작하십시오.

예를 들어 같은 크기의 원으로 시작하면 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

Wikipedia에서 찾은 이미지

우리에게 필요한 표기법이 하나 더 있습니다. 중심이 (x, y) 인 반지름 r 의 원을 가지고 있다면 곡률을 k = ± 1 / r 로 정의 할 수 있습니다 . 일반적으로 k 는 양수이지만 음수 k 를 사용하여 개스킷에있는 다른 모든 원을 둘러싸는 원을 표시 할 수 있습니다 (즉, 모든 접선이 내부에서 해당 원에 닿음). 그런 다음 (k, x * k, y * k) 와 같이 삼중 숫자로 원을 지정할 수 있습니다 .

이 질문의 목적을 위해 양의 정수 k 와 합리적인 xy로 가정 합니다.

이러한 서클에 대한 추가 예제 는 Wikipedia 기사에서 찾을 수 있습니다 .

이 기사에는 통합 개스킷 관한 흥미로운 것들이 있습니다 ( 원이 있는 다른 재미있는 것들 중에서도).

도전

주어진됩니다 4 모양을 각각의 원 사양을 (14, 28/35, -112/105). 편리한 목록 형식과 나누기 연산자를 사용하여 eval원하는 경우 간단히 입력 할 수 있습니다 . 4 개의 원이 실제로 서로 접하고 첫 번째 원이 음의 곡률을 가지고 있다고 가정 할 수 있습니다. 그것은 당신이 이미 다른 세 곳의 주변 아폴로니아 원을 받았다는 것을 의미합니다. 유효한 예제 입력 목록은 챌린지 하단을 참조하십시오.

이 입력이 주어지면 아폴로니아 개스킷을 그리는 프로그램이나 함수를 작성하십시오.

함수 인수 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]]

귀하의 예시 그림은 첫 번째 수술 후 "내부"아폴로니아 원만 포함한 것으로 보입니다.
Sparr

@Sparr 무슨 말인지 잘 모르겠습니다. 첫 번째 작업 후에 두 개의 아폴로니아 원 중 하나가 이미 존재하며 (현재 반복에 대해 선택하지 않은 원래 부모 원) 다른 솔루션 만 찾고 있습니다.
Martin Ender

걱정 마세요, 당신 말이 맞아요
Sparr

답변:


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]]이 주어진 경우 (잉크 스케이프를 사용하여 PNG로 변환) 출력

개스킷 2/3/6/7


237 바이트에서 너무 오래 걸리는 경우 (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 형식이므로 김프가 계속로드하더라도 사양을 엄격하게 따르지는 않습니다. 엄격한 준수가 필요한 n경우 마지막 뒤에를 삽입 하십시오 !.

래스터 화는 각 원에 대해 각 픽셀을 테스트하는 것이므로 소요 시간은 픽셀 수에 원 수를 곱한 것과 거의 선형입니다. 모든 것을 10 배 축소하여

'/'/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로 그래픽 출력을 할 수 있다고 생각하지 않았을 것입니다 ...
Beta Decay

12

자바 스크립트 ( 418,410 바이트)

함수로 구현 :

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 사양의 요구 사항을 준수하지 않는 브라우저에서는 작동하지 않으므로 해당 버그를 해결 하는 약간 더 긴 버전 을 제공합니다 . 브라우저는 예를 들어 잉크 스케이프보다 SVG를 덜 정확하게 렌더링 할 수 있습니다. 비록 잉크 스케이프는 인용 속성에서 조금 더 엄격하지만).

를 사용하여 8 바이트를 절약 할 수 document.write있지만 jsFiddle을 심각하게 중단시킵니다.


1
ES6으로 함수를 정의하고 예를 들어 S/c[0]변수에 저장 한 다음 Math.abs삼항 연산자 등을 제거 하여 더 많은 비용을 절약 할 수 있습니다 .
Ingo Bürk

@ IngoBürk, ES6 경로를 사용하려면 CoffeeScript로 작성하십시오.
Peter Taylor

호스트 c99.nl을 사용하십시오. document.write를 허용합니다.
xem

2
이에 대한 답변을 보게되어
반갑습니다

임시 변수에 대한 @ IngoBürk의 제안으로 업데이트되었습니다. 제거 Math.abs하면 실제로 캐릭터가 필요합니다.
피터 테일러

6

Mathematica 289 자

http://arxiv.org/pdf/math/0101066v1.pdf 정리 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}}

여기에 이미지 설명을 입력하십시오


어떻게 입력합니까?
Martin Ender

@{{-1, 0, 0}, {2, 1, 0}, {2, -1, 0}, {3, 0, 2}}마지막 줄 에 추가 하여 함수 인수로 @ MartinBüttner
박사 belisarius

@ MartinBüttner 테스트하려면 먼저 50/h대신을 사용해보십시오 400/h. 결과가 더 빨라질 것입니다. 또한, Dynamic@Length@a기능을 실행하기 전에 입력하여 진행 상황을 모니터링 할 수 있습니다
Dr. belisarius

Instructions for testing this answer (with a reduced number of circles) without Mathematica installed: 1) pastebin 에서이 파일 을 다운로드 하여 * .CDF로 저장하십시오. 2) Wolfram Research 의 무료 CDF 환경 (작은 파일 아님 )을 다운로드하여 설치 하십시오 . 즐겨. 작동하는지 알려주세요!-참고 : 계산 속도가 느립니다. 그래픽이 나타날 때까지 기다리십시오.
Dr. belisarius

"매우 비효율적 인"의견은 무엇을 의미합니까? (애니메이션을 보면서) 대부분의 원을 적어도 두 번 그리는 것입니까? 복잡한 데카르트 방식은 본질적으로 효율적이라고 생각합니다.
피터 테일러

4

메이플 (960 바이트)

Descartes Theorem을 사용하여 Apollonian Gasket을 생성 한 다음 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.