Намалюйте аполонівську прокладку


28

З огляду на три взаємно дотичних кола, ми завжди можемо знайти ще два кола, дотичні до всіх трьох з них. Ці два називаються аполонськими колами . Зауважте, що одне з аполонських кіл може бути насправді навколо трьох початкових кіл.

Починаючи з трьох дотичних кіл, ми можемо створити фрактал під назвою аполонівська прокладка , виконавши наступний процес:

  1. Назвіть початкові 3 кола батьківських кіл
  2. Знайдіть два аполлонські кола батьківських кіл
  3. Для кожного аполонівського кола:
    1. Для кожної пари з трьох пар батьківських кіл:
      1. Зателефонуйте до аполонівського кола та двох батьківських кіл новий набір батьківських кіл та почніть із кроку 2.

Наприклад, починаючи з кіл однакового розміру, отримуємо:

введіть тут опис зображення

Зображення знайдено у Вікіпедії

Є ще один біт позначень, який нам потрібен. Якщо у нас є коло радіуса r з центром (x, y) , ми можемо визначити його кривизну як k = ± 1 / r . Зазвичай k буде позитивним, але ми можемо використовувати негативний k для позначення кола, що охоплює всі інші кола в прокладці (тобто всі дотичні дотики до цього кола зсередини). Тоді ми можемо вказати коло з трійкою чисел: (k, x * k, y * k) .

Для цього питання будемо вважати додатне ціле k і раціональне x і y .

Подальші приклади таких кругів можна знайти у статті Вікіпедії .

У цій статті також є цікаві речі про цілісні прокладки (серед інших цікавих речей з кружечками).

Змагання

Вам будуть надані 4 специфікації кола, кожне з яких буде виглядати так (14, 28/35, -112/105). Ви можете використовувати будь-який формат списку та оператор поділу, який є зручним, таким, що ви можете просто evalввести, якщо хочете. Можна припустити, що 4 кола дійсно дотичні один до одного і що перше з них має негативну кривизну. Це означає, що вам вже дано оточуючий Аполлонський коло інших трьох. Список дійсних прикладних входів див. У нижній частині завдання.

Напишіть програму або функцію, яка, враховуючи цей вхід, малює аполонівську прокладку.

Ви можете взяти введення через аргумент функції, ARGV або STDIN і або вивести фрактал на екрані, або записати його у файл зображення у обраному вами форматі.

Якщо отримане зображення буде растеризоване, воно має бути не менше 400 пікселів з кожної сторони, менше ніж 20% прокладки навколо найбільшого кола. Ви можете припинити повторення, коли ви дістанете кола, радіус яких менший за 400-ту найбільшу вхідну окружність, або кола, менші за піксель, залежно від того, що відбудеться першим.

Ви повинні малювати лише контури кола, не повні диски, але кольори фону та лінії - це ваш вибір. Обриси не повинні бути ширше 200-ти діаметра зовнішніх кіл.

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.

Приклади введення

Ось усі інтегральні прокладки зі статті Вікіпедії, перетворені у встановлений формат введення:

[[-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 Я не впевнений, що ти маєш на увазі. Після першої операції одне з двох аполлонських кіл уже існує (оригінальне батьківське коло, яке ви не вибрали для поточної ітерації), і ви шукаєте лише інше рішення.
Мартін Ендер

Неважливо, ти маєш рацію, я неправильно читав.
Спарр

Відповіді:


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 та генерує SVG-файл для stdout. На жаль, для демонстрації в Інтернеті потрібно небагато часу, але перероблена версія, яка рано перериває, може дати вам уявлення.

За [[-2, 0, 0], [3, 1/2, 0], [6, -2, 0], [7, -3/2, 2]]даним входом вихід (перетворений у PNG за допомогою InkScape) є

прокладка 2/3/6/7


У 237 байт і занадто довго (я екстраполюю, що для отримання подібного виходу, ніж у вищезгаданому чорно-білому), знадобиться трохи більше тижня:

'/'/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 разів,

'/'/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 зображення

(перетворений у PNG за допомогою GIMP). За 36 годин він створив 401x401

401x401 зображення


3
Я ніколи б не подумав, що ти можеш зробити графічний вихід із Golfscript ...
бета-розпад

12

JavaScript ( 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 менш точно, ніж наприклад Inkscape, хоча Inkscape трохи суворіший щодо атрибутів котирування).

Зауважте, що 8 байтів можна зберегти за допомогою document.write, але це серйозно загрожує jsFiddle.


1
Можливо, ви можете зекономити більше, визначивши функцію з ES6 та зберігаючи, наприклад, S/c[0]у змінній, а потім також позбувшись Math.absіз потрійним оператором тощо.
Ingo Bürk,

@ IngoBürk, якби я збирався їхати по маршруту ES6, тоді я б написав це в CoffeeScript.
Пітер Тейлор

використовувати хост c99.nl. Це дозволяє document.write.
xem


Оновлено пропозицією @ IngoBürk щодо тимчасової змінної. Усунення Math.absнасправді коштувало б характеру.
Пітер Тейлор

6

Математика 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}}

введіть тут опис зображення


Як ви приймаєте внесок?
Мартін Ендер

@ MartinBüttner як аргумент функції, додавши @{{-1, 0, 0}, {2, 1, 0}, {2, -1, 0}, {3, 0, 2}}до останнього рядка
Dr. belisarius

@ MartinBüttner Якщо ви збираєтеся протестувати, спробуйте спершу 50/hзамість 400/h. Ви швидше отримаєте результат. також ви можете стежити за ходом, ввівши Dynamic@Length@aперед виконанням функції
д-р belisarius

Instructions for testing this answer (with a reduced number of circles) without Mathematica installed: 1) Завантажте це з pastebin і збережіть його як * .CDF 2) Завантажте та встановіть вільне середовище CDF з Wolfram Research за адресою (не маленький файл). Насолоджуйтесь. Скажіть, чи спрацьовує це! - Примітка: Calcs повільний, зачекайте, поки з’явиться графіка.
Доктор Белісарій

Що стосується коментаря "високоефективного"? Це що (дивлячись на анімацію) ви, мабуть, малюєте більшість кіл хоча б двічі? Я думаю, що комплексний Декартський підхід є таким самим ефективним, наскільки він ефективний.
Пітер Тейлор

4

Клен (960 байт)

Я використовував теорему Декарта для створення аполонівської прокладки, а потім використовував схему схеми Клена для її побудови. Якщо у мене є час, я хочу ще більше пограти в це поле і змінити його на 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]]);

введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.