Tessitura di guarnizioni: disegna un nodo Sierpiński


33

Dato un numero intero N> = 2, produce un'immagine che mostra un nodo Sierpiński di grado N.

Ad esempio, qui ci sono nodi di grado 2, 3, 4 e 5:

Grado 2 Grado 3 Grado 4 Grado 5

Fare clic sulle immagini per visualizzare a schermo intero (maggiore è il grado più grande è l'immagine).

specificazione

  1. Un nodo Sierpiński di grado N viene disegnato usando i vertici di un triangolo Sierpiński di grado N come punti guida. Un triangolo Sierpiński di grado N è costituito da tre triangoli Sierpiński di grado N-1 disposti in un triangolo più grande. Un triangolo Sierpiński di grado 0 è un triangolo equilatero.
  2. I triangoli dei componenti più piccoli hanno una lunghezza laterale 64, dando al triangolo Sierpiński su cui si basa il nodo una lunghezza laterale complessiva di 64 * 2 ^ N
  3. Il centro del triangolo esterno è posizionato al centro dell'immagine. Questo non dà uguale spazio bianco in alto e in basso.
  4. L'output è un'immagine quadrata di lunghezza laterale soffitto (64 * 2 ^ N * 2 / ROOT3)dove soffitto (x)è ceiling(x), il numero intero più piccolo maggiore o uguale a x. Questo è appena abbastanza grande per il vertice superiore del triangolo Sierpiński sottostante da essere contenuto nell'immagine quando il centro del triangolo è al centro dell'immagine.
  5. La singola curva deve passare sopra e sotto se stessa, alternandosi rigorosamente. Le soluzioni possono scegliere tra under then over, oppure over then under.
  6. Le immagini di esempio mostrano il primo piano nero e lo sfondo bianco. Puoi scegliere due colori facilmente distinguibili. L'antialiasing è consentito ma non necessario.
  7. Non devono esserci spazi dove si incontrano due archi o dove la curva passa sopra o sotto se stessa.
  8. L'output può essere in qualsiasi file di immagine in formato raster o in qualsiasi file di immagine in formato vettoriale che includa una dimensione di visualizzazione predefinita corretta. Se si visualizza direttamente sullo schermo, questo deve essere in una forma che consenta allo scorrimento di vedere l'immagine intera quando è più grande dello schermo.

Determinazione del centro, del raggio e dello spessore dell'arco

  1. Il nodo è costruito come una serie di archi circolari che si incontrano in punti in cui le loro tangenti sono parallele, per unire senza soluzione di continuità. Questi archi vengono visualizzati come settori anulari (archi con spessore).
  2. I centri di questi archi sono i vertici dei più piccoli triangoli sottosopra. Ciascuno di questi vertici è il centro di esattamente un arco.
  3. Ogni arco ha un raggio di 64 * ROOT3 / 2
  4. L'eccezione è che gli archi nei tre triangoli più esterni (agli angoli del triangolo grande) hanno un centro che è il punto medio dei due vertici interni adiacenti, e quindi hanno un raggio di 64 * (ROOT3 / 2-1 / 2)
  5. Ogni arco è rappresentato con uno spessore totale (differenza tra raggio interno e raggio esterno) di 64 * (ROOT3 / 2) / 4e i bordi neri di questo hanno ciascuno uno spessore di 64 * (ROOT3 / 2) / 16La curva deve avere questi bordi e non essere solo una striscia solida.

Unità di misura

  1. Tutte le distanze sono in pixel (1 è la distanza orizzontale o verticale tra 2 pixel adiacenti).
  2. La radice quadrata di 3 deve avere una precisione di 7 cifre significative. Cioè, i tuoi calcoli devono essere equivalenti all'utilizzo di un ROOT3 tale che1.7320505 <= ROOT3 < 1.7320515

punteggio

Vince il codice più breve in byte.


Per quelli che si chiedono, N = 0 e N = 1 non sono inclusi perché corrispondono a un cerchio e un trifoglio, che non corrispondono del tutto allo schema che si applica per N> = 2. Mi aspetto che la maggior parte degli approcci a questa sfida debba aggiungere un codice di caso speciale per 0 e 1, quindi ho deciso di ometterli.


1
Aiuterebbe avere un diagramma per mostrare a cosa si riferiscono tutti i numeri?
trichoplax,

Prima di giocare a golf la mia risposta / aggiungere angoli, sono davvero necessarie 7 cifre significative per piccoli dettagli come lo spessore della linea, ecc.? Un'accuratezza come "7 cifre significative o 1 pixel, qualunque sia la più grande" sembra più appropriata.
Level River St,

@LevelRiverSt poiché la dimensione dell'immagine si ridimensiona con l'input, anche 7 cifre significative non sono sufficienti per una precisione di 1 pixel per N. più grandi Dopo aver discusso in chat ho impostato 7 cifre significative, in modo che tutte le risposte siano mantenute invariate standard.
trichoplax,

Sì, è necessario per il ridimensionamento dell'immagine per N. 7 di dimensioni significative su un'immagine 1000000 x 1000000 corrisponde a 0,1 pixel, ma con calcoli intermedi potrebbe essere peggio di così. Penso solo stroke-width:3.464102e simili è un po 'eccessivo se l'idea fosse quella di ottenere una precisione di 1 pixel. Andrò avanti e lo includerò in questo modo, però, se questa è la sentenza.
Level River St,

Risposte:


27

Ruby, 1168 932

Corretto un errore della scorsa notte, più golf da fare dopo aver chiarito.

Questo è (attualmente) un programma completo che accetta un numero da stdin e invia un svgfile a stdout. Ho scelto svg perché sapevo che era possibile soddisfare tutti i requisiti della domanda, ma aveva alcuni problemi. in particolare SVG supporta solo archi di cerchi come parte pathdell'oggetto e non li definisce in termini di centro ma piuttosto di due punti finali.

Codice

n=gets.to_i
r=64*w=0.75**0.5
m=1<<n-2
z=128*m/w
a=(s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
")%[0,r-r*m*8/3]+"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"
p=2
m.times{|i|(i*2+1).times{|j|(p>>j)%8%3==2&&a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}
p^=p*4}
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

Uscita N = 4

riscalato dallo scambio di stack. Sembra molto meglio come originale.

inserisci qui la descrizione dell'immagine Spiegazione

All'inizio ho considerato qualcosa come http://euler.nmt.edu/~jstarret/sierpinski.html in cui il triangolo è suddiviso in tre fili di colori diversi, ognuno dei quali forma un percorso da un angolo all'altro. I cerchi incompleti sono mostrati come esagoni incompleti lì. i cerchi di iscrizione all'interno degli esagoni mostrano che il raggio del cerchio dovrebbe essere sqrt(3)/2volte la lunghezza laterale. I trefoli potrebbero essere ricostruiti in modo ricorsivo come mostrato, ma c'è un'ulteriore complicazione perché gli angoli devono essere arrotondati ed è difficile sapere in quale direzione curvare, quindi non ho usato questo approccio.

Quello che ho fatto è stato il seguente.

Nell'immagine qui sotto puoi vedere che ci sono colpi di scena orizzontali appartenenti alle unità N = 2 (in verde) disposte in un triangolo sierpinski e colpi di scena aggiuntivi in ​​ponte (in blu).

È risaputo che i numeri dispari sul triangolo di Pascal formano un triangolo sierpinski. Un triangolo sierpinski di cifre binarie può essere ottenuto in modo analogo, iniziando con il numero p=1e ripetutamente itorandolo con p<<1.

Ho modificato questo approccio, a partire da p=2e iterativamente xoring con p*4. Questo dà un triangolo sierpinski alternato a colonne di zeri.

Ora possiamo spostare i diritti p e ispezionare gli ultimi tre bit usando %8. Se lo sono, 010dobbiamo disegnare una torsione verde appartenente a un'unità N = 2. se lo sono, 101dobbiamo disegnare una svolta blu, a ponte. Per testare entrambi questi numeri insieme troviamo il modulo %3e se questo è 2 dobbiamo disegnare il twist.

Infine, oltre ai colpi di scena orizzontali, realizziamo due copie ruotate di 120 e 240 gradi per disegnare i colpi di scena diagonali e completare l'immagine. Non resta che aggiungere gli angoli.

Codice commentato

n=gets.to_i

#r=vertical distance between rows 
r=64*w=0.75**0.5

#m=number of rows of horizontal twists
m=1<<n-2

#z=half the size of the viewport
z=128*m/w

#s=SVG common to all paths
s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
"

#initialize a with SVG to draw top corner loop. Set k and l to the SVG common to all arcs of 58*w and 70*w radius 
a=s%[0,r-r*m*8/3]+
"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"

#p is the pattern variable, top row of twists has one twist so set to binary 00000010
p=2

#loop vertically and horizontally
m.times{|i|
 (i*2+1).times{|j|

   #leftshift p. if 3 digits inspected are 010 or 101 
   (p>>j)%8%3==2&&

   #append to a, the common parts of a path...
   a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+

   #...and the SVG for the front strand and left and right parts of the back strand (each strand has 2 borders)
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}

#modify the pattern by xoring with 4 times itself for the next row
p^=p*4}

#output complete SVG of correct size with three copies of the finished pattern rotated through 0,120,240 degrees.
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

inserisci qui la descrizione dell'immagine


Dove dici "Sembra molto meglio dell'originale", potrebbe valere la pena aggiungere qualcosa del tipo "(fai clic sull'immagine per vedere a schermo intero)" per chi non se ne rende conto.
trichoplax,

@trichoplax non mi era mai venuto in mente di fare clic sull'immagine. Comunque, questo è un PNG, perché lo scambio di stack non accetta le immagini svg, quindi i bordi sono deliberatamente sfocati. Il mio file SVG locale ha bordi molto più nitidi e ha un aspetto molto migliore.
Level River St,

@trichoplax correzione rapida sulla dimensione dell'immagine fatta. Golferà di più un altro giorno.
Level River St

1
+1 ottimo lavoro. Mi piace particolarmente la spiegazione dettagliata con il diagramma con codice colore.
trichoplax,

1
Il collegamento ipertestuale è morto.
mbomb007,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.