Vẽ một miếng đệm Apollonia


28

Cho ba vòng tròn tiếp tuyến lẫn nhau, chúng ta luôn có thể tìm thấy hai vòng tròn tiếp tuyến với cả ba vòng tròn đó. Hai người này được gọi là vòng tròn Apollonia . Lưu ý rằng một trong các vòng tròn Apollonia thực sự có thể nằm xung quanh ba vòng tròn ban đầu.

Bắt đầu từ ba vòng tròn tiếp tuyến, chúng ta có thể tạo ra một mảnh nhỏ gọi là miếng đệm Apollonia , theo quy trình sau:

  1. Gọi 3 vòng tròn ban đầu là vòng tròn cha
  2. Tìm hai vòng tròn Apollonia của vòng tròn cha mẹ
  3. Đối với mỗi vòng tròn Apollonia:
    1. Đối với mỗi cặp của ba cặp vòng tròn cha mẹ:
      1. Gọi vòng tròn Apollonia và hai vòng tròn cha mẹ là nhóm vòng tròn cha mẹ mới và bắt đầu lại từ bước 2.

Ví dụ: bắt đầu với các vòng tròn có kích thước bằng nhau, chúng tôi nhận được:

nhập mô tả hình ảnh ở đây

Hình ảnh được tìm thấy trên Wikipedia

Chúng ta cần thêm một chút ký hiệu. Nếu chúng ta có một vòng tròn bán kính r với tâm (x, y) , chúng ta có thể định nghĩa độ cong của nó là k = ± 1 / r . Thông thường k sẽ dương, nhưng chúng ta có thể sử dụng k âm để biểu thị vòng tròn bao quanh tất cả các vòng tròn khác trong miếng đệm (tức là tất cả các tiếp tuyến chạm vào vòng tròn đó từ bên trong). Sau đó, chúng ta có thể chỉ định một vòng tròn với một bộ ba số: (k, x * k, y * k) .

Đối với mục đích của câu hỏi này, chúng tôi sẽ giả sử số nguyên dương k và hợp lý xy .

Các ví dụ khác cho các vòng tròn như vậy có thể được tìm thấy trong bài viết Wikipedia .

Ngoài ra còn có một số nội dung thú vị về các miếng đệm tích hợp trong bài viết này (trong số những điều thú vị khác với vòng tròn).

Các thách thức

Bạn sẽ được cung cấp 4 thông số kỹ thuật hình tròn, mỗi thông số sẽ như thế nào (14, 28/35, -112/105). Bạn có thể sử dụng bất kỳ định dạng danh sách và toán tử phân chia thuận tiện, như vậy bạn có thể chỉ cần evalnhập liệu nếu bạn muốn. Bạn có thể cho rằng 4 vòng tròn thực sự tiếp xúc với nhau và đầu tiên trong số chúng có độ cong âm. Điều đó có nghĩa là bạn đã được đưa ra vòng tròn Apollonia xung quanh của ba người kia. Để biết danh sách các ví dụ đầu vào hợp lệ, xem phần dưới cùng của thử thách.

Viết chương trình hoặc hàm, với đầu vào này, vẽ một miếng đệm Apollonia.

Bạn có thể nhận đầu vào thông qua đối số chức năng, ARGV hoặc STDIN và hiển thị fractal trên màn hình hoặc ghi nó vào tệp hình ảnh theo định dạng bạn chọn.

Nếu hình ảnh thu được được rasterized, nó phải có ít nhất 400 pixel ở mỗi bên, với phần đệm dưới 20% xung quanh vòng tròn lớn nhất. Bạn có thể ngừng đệ quy khi bạn tiếp cận các vòng tròn có bán kính nhỏ hơn 400 vòng tròn đầu vào lớn nhất hoặc các vòng tròn nhỏ hơn pixel, tùy theo trường hợp nào xảy ra trước.

Bạn phải chỉ vẽ đường viền vòng tròn, không phải đĩa đầy đủ, nhưng màu nền và đường kẻ là lựa chọn của bạn. Các đường viền không được rộng hơn 200 đường kính vòng tròn bên ngoài.

Đây là mã golf, vì vậy câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.

Ví dụ đầu vào

Dưới đây là tất cả các miếng đệm tích hợp từ bài viết Wikipedia được chuyển đổi sang định dạng đầu vào được quy định:

[[-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]]

Ví dụ minh họa của bạn dường như chỉ bao gồm các vòng tròn apollonia "bên trong" sau thao tác đầu tiên.
Sparr

@Sparr Tôi không chắc ý của bạn là gì. Sau thao tác đầu tiên, một trong hai vòng tròn Apollonia đã tồn tại (vòng tròn gốc ban đầu mà bạn không chọn cho lần lặp hiện tại) và bạn chỉ tìm kiếm giải pháp khác.
Martin Ender

Đừng bận tâm, bạn nói đúng, tôi đã đọc sai.
Sparr

Câu trả lời:


12

GolfScript (vectơ 289 byte / raster 237 byte)

Ở mức 288 byte và thực thi trong thời gian hợp lý:

'/'/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>'

Thao tác này sẽ nhập dữ liệu vào stdin và tạo tệp SVG cho thiết bị xuất chuẩn. Thật không may, nó mất quá nhiều thời gian cho một bản demo trực tuyến, nhưng một phiên bản được tinh chỉnh sớm bị hủy bỏ có thể cho bạn một ý tưởng.

Với đầu vào [[-2, 0, 0], [3, 1/2, 0], [6, -2, 0], [7, -3/2, 2]]các đầu ra (chuyển đổi sang PNG với Inkscape) được

gioăng 2/3/6/7


Với tốc độ 237 byte và mất quá nhiều thời gian (tôi ngoại suy rằng sẽ chỉ mất hơn một tuần để tạo ra đầu ra tương tự như trên, mặc dù ở chế độ đen trắng một bit):

'/'/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=},!}/

Đầu ra là định dạng NetPBM không có dòng mới, vì vậy có thể không tuân thủ nghiêm ngặt thông số kỹ thuật, mặc dù GIMP vẫn sẽ tải nó. Nếu cần tuân thủ nghiêm ngặt, chèn một cái nsau cùng !.

Việc rasterisation là bằng cách kiểm tra từng pixel theo từng vòng tròn, do đó thời gian thực hiện khá tuyến tính với số lượng pixel nhân với số lượng vòng tròn. Bằng cách hạ thấp mọi thứ theo hệ số 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=},!}/

sẽ chạy trong 10 phút và sản xuất

Hình ảnh 81x81

(được chuyển đổi thành PNG với GIMP). Trong 36 giờ, nó đã tạo ra 401x401

Hình ảnh 401x401


3
Tôi chưa bao giờ nghĩ rằng bạn có thể thực hiện đầu ra đồ họa với Golfscript ...
Beta Decay

12

JavaScript ( 418 410 byte)

Được thực hiện như một chức năng:

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}

Bản demo trực tuyến (lưu ý: không hoạt động trong các trình duyệt không tuân thủ các yêu cầu của thông số kỹ thuật SVG liên quan đến kích thước ngầm, vì vậy tôi cung cấp một phiên bản dài hơn chút , hoạt động xung quanh lỗi đó; trình duyệt cũng có thể hiển thị SVG kém chính xác hơn so với Inkscape, mặc dù Inkscape nghiêm ngặt hơn một chút về trích dẫn thuộc tính).

Lưu ý rằng 8 byte có thể được lưu bằng cách sử dụng document.write, nhưng điều đó thực sự gây khó khăn cho jsFiddle.


1
Bạn có thể có thể tiết kiệm nhiều hơn bằng cách xác định hàm với ES6 và lưu trữ, ví dụ: S/c[0]trong một biến và sau đó loại bỏ Math.absvới một toán tử ternary, v.v.
Ingo Bürk

@ IngoBürk, nếu tôi định đi theo con đường ES6 thì tôi sẽ viết nó bằng CoffeeScript thay thế.
Peter Taylor

sử dụng máy chủ c99.nl. Nó cho phép document.write.
xem

2
Thật

Được cập nhật với đề xuất của @ IngoBürk cho một biến tạm thời. Loại bỏ Math.absthực sự sẽ tốn một nhân vật.
Peter Taylor

6

Toán học 289 ký tự

Bằng cách giải hệ phương trình song tuyến theo http://arxiv.org/pdf/math/0101066v1.pdf Định lý 2.2 (rất kém hiệu quả).

Không gian không cần thiết, vẫn chơi golf:

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))] &

Một hình ảnh động giảm kích thước với đầu vào {{-13, 0, 0}, {23, 10/13, 0}, {30, -84/65, -1/5}, {38, -44/65, 9/5}}

nhập mô tả hình ảnh ở đây


Làm thế nào để bạn có đầu vào?
Martin Ender

@ MartinBüttner là một đối số chức năng, bằng cách thêm @{{-1, 0, 0}, {2, 1, 0}, {2, -1, 0}, {3, 0, 2}}vào dòng cuối cùng
Tiến sĩ belisarius

@ MartinBüttner Nếu bạn đang đi để kiểm tra nó thử đầu tiên với 50/hthay vì 400/h. Bạn sẽ nhận được kết quả nhanh hơn. đồng thời, bạn có thể theo dõi tiến trình bằng cách nhập Dynamic@Length@atrước khi thực hiện chức năng
Tiến sĩ belisarius

Instructions for testing this answer (with a reduced number of circles) without Mathematica installed: 1) Tải xuống tệp này từ pastebin và lưu dưới dạng * .CDF 2) Tải xuống và cài đặt môi trường CDF miễn phí từ Wolfram Research tại (không phải là một tệp nhỏ). Thưởng thức. Hãy cho tôi biết nếu nó hoạt động! - Lưu ý: Calcs chậm, chờ đồ họa xuất hiện.
Tiến sĩ belisarius

Nhận xét "không hiệu quả cao" đề cập đến điều gì? Có phải là (nhìn vào hình ảnh động) rõ ràng bạn đang vẽ hầu hết các vòng tròn ít nhất hai lần? Tôi nghĩ rằng phương pháp Descartes phức tạp vốn đã hiệu quả như nó có.
Peter Taylor

4

Maple (960 byte)

Tôi đã sử dụng Định lý Descartes để tạo ra Goll Apollonia và sau đó sử dụng hệ thống âm mưu của Maple để vẽ nó. Nếu tôi có thời gian, tôi muốn chơi gôn thêm và đổi nó thành Python (Maple chắc chắn không phải là tốt nhất cho fractals). Đây là một liên kết đến một người chơi Maple miễn phí nếu bạn muốn chạy mã của tôi.

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:

Một số miếng đệm mẫu

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

nhập mô tả hình ảnh ở đây

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

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.