Disegna una stella di Natale / dodecaedro stellato


10

Le stelle di carta sono una cosa importante nella mia famiglia a Natale, quindi ho pensato che una virtuale sarebbe stata bella.

Di seguito un'immagine di un dodecaedro regolare (da https://en.wikipedia.org/wiki/Dodecahedron , attribuito all'autore ivi citato).

inserisci qui la descrizione dell'immagine

Il processo di stellazione (wikipedia) applicato a un poliedro comporta l'estensione delle facce fino a quando non incrociano altre facce. Quindi partendo dal dodecaedro regolare, otteniamo le seguenti forme:

Piccolo dodecaedro stellato, grande dodecaedro e grande dodecaedro stellato

Immagine da http://jwilson.coe.uga.edu/emat6680fa07/thrash/asn1/stellations.html

inserisci qui la descrizione dell'immagine

Queste sono le tre possibili Stellazioni del dodecaedro (Wolfram). Formano una progressione naturale dal dodecaedro, al piccolo dodecaedro stellato, al grande dodecaedro e al grande dodecaedro stellato, mentre estendiamo sempre più le facce.

Compito

Il programma o la funzione dovrebbe visualizzare o inviare a un file immagine uno dei seguenti poliedri: dodecaedro normale, dodecaedro piccolo stellato, dodecaedro grande o dodecaedro grande stellato .

Lo schema dei colori dovrebbe essere come la seconda immagine sopra. Ognuna delle sei coppie di facce opposte deve essere uno dei sei colori Rosso, Giallo, Verde, Ciano, Blu e Magenta. Puoi utilizzare i colori predefiniti con questi nomi nella tua lingua o nella sua documentazione oppure utilizzare i colori FF0000, FFFF00, 00FF00, 00FFFF, 0000FF e FF00FF (puoi attenuarli riducendo l'intensità a un minimo del 75%, se lo desideri, ad esempio riducendo le F in C.)

Si noti che definiamo una "faccia" come tutte le aree sullo stesso piano. Pertanto, nelle immagini sopra la faccia anteriore è gialla (e anche la faccia posteriore parallela sarebbe gialla).

Lo sfondo deve essere nero, grigio o bianco. I bordi possono essere omessi, ma dovrebbero essere neri se disegnati.

Regole

Il poliedro visualizzato deve avere una larghezza compresa tra 500 e 1000 pixel (la larghezza è definita come la distanza massima tra due vertici visualizzati).

Il poliedro visualizzato deve essere in proiezione prospettica (punto di vista ad almeno 5 larghezze dal poliedro) o in proiezione ortografica (effettivamente una proiezione prospettica con il punto di vista all'infinito).

Il poliedro deve essere visualizzabile da qualsiasi angolazione. (Non è accettabile scegliere l'angolazione più semplice possibile e creare una forma 2D codificata.) L'angolo può essere specificato dall'utente in uno dei seguenti modi:

  1. Immissione di tre angoli corrispondenti a tre rotazioni, da stdin o come parametri di funzione o riga di comando. Questi possono essere gli angoli di Eulero (dove la prima e l'ultima rotazione sono attorno allo stesso asse) o gli angoli di Tait-Bryan (dove c'è una rotazione ciascuno attorno all'asse x, ye z) https://en.wikipedia.org/ wiki / Euler_angles (in poche parole, tutto procede fintanto che ogni rotazione è attorno all'asse x, yo z e le rotazioni consecutive riguardano assi perpendicolari.)

  2. Possibilità per l'utente di ruotare il poliedro in incrementi di non più di 10 gradi attorno agli assi xey e aggiornare il display, qualsiasi numero arbitrario di volte (assumendo l'asse z perpendicolare allo schermo).

Il poliedro deve essere solido, non wireframe.

Non sono ammessi builtin per disegnare poliedri (ti sto guardando, Mathematica!)

punteggio

Questo è codegolf. Vince il codice più breve in byte.

bonus

Moltiplica il tuo punteggio per 0,5 se non usi builtin per il disegno 3D.

Moltiplica il tuo punteggio per 0,7 se riesci a visualizzare tutte e tre le stellazioni del dodecaedro, selezionabili dall'utente per un numero intero 1-3 immesso da stdin o per parametro di funzione o riga di comando.

Se scegli entrambi i bonus, il tuo punteggio verrà moltiplicato per 0,5 * 0,7 = 0,35

Informazioni utili (fonti come di seguito)

https://en.wikipedia.org/wiki/Regular_dodecahedron

https://en.wikipedia.org/wiki/Regular_icosahedron

Il dodecaedro ha 20 vertici. 8 di questi formano i vertici di un cubo con le seguenti coordinate cartesiane (x, y, z):

(± 1, ± 1, ± 1)

I restanti 12 sono i seguenti (phi è il rapporto aureo)

(0, ± 1 / φ, ± φ)

(± 1 / φ, ± φ, 0)

(± φ, 0, ± 1 / φ)

Lo scafo convesso del piccolo dodecaedro stellato e del grande dodecaedro è ovviamente un dodecaedro regolare. I vertici esterni descrivono un icosaedro.

Secondo Wikipedia i 12 vertici di un icosaedro possono essere descritti in modo simile alle permutazioni cicliche di (0, ± 1, ± φ). I vertici esterni del piccolo dodecaheron stellato e del grande dodecedro (sulla stessa scala del dodecaedro sopra) formano un icosaedro più grande, dove le coordinate dei vertici sono permutazioni cicliche di (0, ± φ ^ 2, ± φ).

Gli angoli tra le facce del dodecaedro e dell'icosaedro sono rispettivamente 2 arctan (phi) e arccos (- (√5) / 3).

Per suggerimenti sulla rotazione, consultare https://en.wikipedia.org/wiki/Rotation_matrix

EDIT: Per errore ho permesso il dodecaedro normale, e non posso ritirarlo ora. Il bonus x0,7 per il disegno di tutti e tre i poliedri stellati rimane. Il giorno di Capodanno rilascerò una taglia di 100 per la risposta che può mostrare la maggior parte dei quattro poliedri, con il codice più breve come pareggio.


@ I legioni incorporati di LegionMammal978 per il disegno di poliedri (ad esempio dodecahedron) non sono consentiti. Alcune lingue hanno strutture per la costruzione di modelli 3D con comandi simili triangle[[a,b,c],[p,q,r],[x,y,z]]. Queste lingue generalmente hanno built-in per ruotare e visualizzare il modello, avendo cura automaticamente di non mostrare facce nascoste, ecc. Soluzioni come queste sono consentite ma non attireranno il bonus. Lo scopo del bonus è quello di consentire alle lingue che non dispongono di queste strutture di essere competitive, e anche di attrarre soluzioni più interessanti.
Level River St,

@ LegionMammal978 haha, sapevo che Mathematica sarebbe stata la lingua che causava problemi. Polyhedrondataè vietato in quanto è chiaramente incorporato per disegnare poliedri. Se la tua risposta non usa i builtin per disegnare poliedri e rispetta le altre regole, allora è accettabile. Il tuo punto sembra essere quello dato che devi colorare correttamente le facce, Polyhedrondatanon ti risparmierebbe comunque molto, quindi in pratica potrebbe essere una restrizione in qualche modo arbitraria. Sono d'accordo in una certa misura, ma è più giusto per tutti se evito di cambiare le regole dopo la pubblicazione.
Level River St,

Risposte:


3

Python 2.7, 949 byte

Ecco la soluzione per il dodecaedro normale tracciato con matplotlib. Il profilo approssimativo per il codice non golfato (non mostrato qui) è stato delineato di seguito:

  • Crea vertici Crea bordi (basato su 3 vicini più vicini, modulo scipy.spatial.KDtree)
  • Crea facce in base a cicli di grafici con lunghezza 5 (modulo networkx)
  • Crea facenormali (e seleziona quelli con il lato esterno normale, numpy.cross)
  • Genera colorazione in base ai normali del viso
  • Stampa usando matplotlib
import itertools as it
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
v=[p for p in it.product((-1,1),(-1,1),(-1,1))]
g=.5+.5*5**.5
v.extend([p for p in it.product((0,),(-1/g,1/g),(-g,g))])
v.extend([p for p in it.product((-1/g,1/g),(-g,g),(0,))])
v.extend([p for p in it.product((-g,g),(0,),(-1/g,1/g))])
v=np.array(v)
g=[[12,14,5,9,1],[12,1,17,16,0],[12,0,8,4,14],[4,18,19,5,14],[4,8,10,6,18],[5,19,7,11,9],[7,15,13,3,11],[7,19,18,6,15],[6,10,2,13,15],[13,2,16,17,3],[3,17,1,9,11],[16,2,10,8,0]]
a=[2,1,0,3,4,5,0,1,2,3,4,5]
fig = plt.figure()
ax = fig.add_subplot((111),aspect='equal',projection='3d')
ax.set_xlim3d(-2, 2)
ax.set_ylim3d(-2, 2)
ax.set_zlim3d(-2, 2)
for f in range(12):
 c=Poly3DCollection([[tuple(y) for y in v[g[f],:]]], linewidths=1, alpha=1)
 c.set_facecolor([(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0)][a[f]])
 ax.add_collection3d(c)
ax.auto_scale_xyz
plt.show()

inserisci qui la descrizione dell'immagine


3

Rubino, 784 byte * 0,5 * 0,7 = 274,4

La mia risposta, quindi non ammissibile per la mia generosità.

Idoneo sia per il bonus incorporato non 3D che per il bonus di disegno di tutte le stellazioni.

->t,n{o=[]
g=->a{a.reduce(:+)/5}
f=->u,v,w,m{x=u.dup;y=v.dup;z=w.dup
15.times{|i|k,l=("i".to_c**(n[i/5]/90.0)).rect
j=i%5
x[j],y[j],z[j]=y[j],x[j]*k+z[j]*l,z[j]*k-x[j]*l}
p=g[x];q=g[y];r=g[z]
a=[0,1,-i=0.382,-1][t]*e=r<=>0
b=[j=1+i,0,j,j][t]*e
c=[-i*j,-i,1,i][t]*e
d=[j*j,j,0,0][t]*e
5.times{|i|o<<"<path id=\"#{"%9.0f"%(z[i]*a+r*b+(z[i-2]+z[i-3])*c+2*r*d+999)}\"
d=\"M#{(x[i]*a+p*b)} #{(y[i]*a+q*b)}L#{(x[i-2]*c+p*d)} #{(y[i-2]*c+q*d)}L#{(x[i-3]*c+p*d)} #{(y[i-3]*c+q*d)}\"
fill=\"##{m}\"/>"}}
a=233
b=377
z=[0,a,b,a,0]
y=[a,b,0,-b,-a]
x=[b,0,-a,0,b]
w=[-b,0,a,0,-b]
f[x,y,z,'F0F']
f[w,y,z,'0F0']
f[y,z,x,'00F']
f[y,z,w,'FF0']
f[z,x,y,'F00']
f[z,w,y,'0FF']
s=File.open("p.svg","w")
s.puts'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-450 -450 900 900">',o.sort,'</svg>'
s.close}

Immettere come parametri di funzione

Un numero intero 0..3 corrispondente a dodecaedro normale, dodecaedro piccolo stellato, dodecaedro grande stellato

Un array di tre numeri interi corrispondenti agli angoli in gradi per le rotazioni attorno agli assi x, y e x (di nuovo) (angoli di Eulero corretti, che consentono di ottenere qualsiasi rotazione).

Emette un file p.svgche può essere visualizzato in un browser web.

Spiegazione

le matrici x, y, z nella parte inferiore del codice contengono le coordinate dei punti esterni di una faccia di un piccolo dodecaedro stellato. Questo può essere inscritto nell'icosaedro i cui 12 vertici sono definiti dalle permutazioni cicliche di (+/- 377, + / - 233, + / - 0). Si noti che 377 e 233 sono numeri consecutivi di Fibonacci e quindi 377/233 è un'eccellente approssimazione al rapporto aureo.

un array aggiuntivo w contiene le coordinate x moltiplicate per -1, equivalenti alla riflessione sul piano x. La funzione f viene chiamata 6 volte, una volta per ciascun colore, con le diverse permutazioni cicliche di x, y, z e w, y, z.

Le tre rotazioni vengono passate come parametri in n []. per usare il peccato e il cos in Ruby, è necessario farlo include Math. per evitare ciò, il coseno e il seno dell'angolo si ottengono elevando la radice quadrata di -1 "i"a una potenza di (angolo in gradi / 90) Le parti reali e immaginarie di questo numero sono memorizzate in k (coseno) el ( seno)

Prima della rotazione, vengono scambiati i valori xey. Quindi la moltiplicazione della matrice viene applicata ai valori y e z per dare una rotazione attorno all'asse x. Lo scambio di valori consente di eseguire le tre rotazioni in un ciclo.

Finora, abbiamo solo un anello di punti. Per ottenere il resto, dobbiamo trovare il centro del pentagono / stella. Questo viene fatto trovando la media delle coordinate dei 5 vertici, che sono memorizzati in p, q, r.

Come accennato in precedenza, viene effettuata una sola chiamata di funzione per colore. Viene verificato il segno di r (la media delle coordinate z, e quindi la coordinata della faccia). Se è positivo, il viso è frontale e quindi visibile. Se è negativo, la faccia è una faccia posteriore. È invisibile e non abbiamo alcuna chiamata di funzione per la faccia opposta. Pertanto, tutte e tre le coordinate devono essere invertite. Il segno di r è memorizzato in e per facilitare ciò.

La faccia è composta da 5 triangoli, i cui vertici sono combinazioni lineari dei vertici esterni del piccolo dodecaedro stellato e il centro della faccia. Nel caso del dodecaedro piccolo stellato, per le punte dei triangoli impostiamo a = 1 e b = 0 (contributo 1 da x, y, z e 0 da p, q, r). Per i 2 vertici di base del triangolo impostiamo c = -0.382 (contributo 1 / rapporto aureo ^ 2 da x, y, z) e d = 1.382 (contributo da p, q, r.) Il motivo del contributo negativo è che i vertici di base del triangolo sono definiti in termini di punte opposte, che si trovano sul lato opposto della faccia. Le coordinate ottenute vengono moltiplicate per e, se necessario.

Le quattro matrici senza nome i cui valori sono assegnati per a,b,c,dcontenere i valori richiesti per il dodecaedro normale, il piccolo dodecaedro stellato, il grande dodecaedro e il grande dodecaedro stellato, selezionati in base alla variabile tNota che per il piccolo dodecaedro stellato e il grande dodecaedro, a + b = c + d = 1. La relazione a + b = c + d si applica alle altre forme, ma viene applicata una scala diversa.

Viene creata una riga di codice svg per ogni triangolo. Questo contiene un ID derivato dalla somma delle coordinate z dei 3 vertici del triangolo, una descrizione dei vertici delle tre coordinate del triangolo e un colore. si noti che osserviamo direttamente l'asse z nella proiezione ortografica. Quindi 2D x = 3D xe 2D y = 3D y. La linea viene aggiunta ah.

infine, dopo che tutte le chiamate di funzione sono terminate, h viene ordinato in modo tale che i triangoli con il valore z più alto (in primo piano) vengano tracciati per ultimi e l'intera cosa venga salvata come file svg con il testo dell'intestazione e del piè di pagina appropriato.

Non registrato nel programma di test

h=->t,n{                                              #t=type of polygon,n=angles of rotation
o=[]                                                  #array for output
g=->a{a.reduce(:+)/5}                                 #auxiliary function for finding average of 5 points

f=->u,v,w,m{x=u.dup;y=v.dup;z=w.dup                   #function to take 5 points u,v,w and plot one face (5 triangles) of the output in colour m 

  15.times{|i|                                        #for each of 3 rotation angle and 5 points
    k,l=("i".to_c**(n[i/5]/90.0)).rect                #calculate the cos and sine of the angle, by raising sqrt(-1)="i" to a power
    j=i%5                                             #for each of the 5 points
    x[j],y[j],z[j]=y[j],x[j]*k+z[j]*l,z[j]*k-x[j]*l}  #swap x and y, then perform maxtrix rotation on (new) y and z.

  p=g[x];q=g[y];r=g[z]                                #find centre p,q,r of the face whose 5 points (in the case of small stellated dodecahedron) are in x,y,z

  e=r<=>0                                             #if r is positive, face is front. if negative, face is back, so we need to transform it to opposite face.
  a=[0,              1,    -0.382,    -1][t]*e        #contribution of 5 points x,y,z to triangle tip vertex coordinates
  b=[1.382,          0,     1.382,     1.382][t]*e    #contribution of centre p,q,r to triangle tip vertex coordinates
  c=[-0.528,        -0.382, 1,         0.382][t]*e    #contribution of 5 points x,y,z to coordinates of each triangle base vertex 
  d=[1.901,          1.382, 0,         0][t]*e        #contribution of centre p,q,r to coordinates of each triangle base vertex

  5.times{|i|
  o<<"<path id=\"#{"%9.0f"%(z[i]*a+r*b+(z[i-2]+z[i-3])*c+2*r*d+999)}\"
d=\"M#{(x[i]*a+p*b)} #{(y[i]*a+q*b)}L#{(x[i-2]*c+p*d)} #{(y[i-2]*c+q*d)}L#{(x[i-3]*c+p*d)} #{(y[i-3]*c+q*d)}\"
fill=\"##{m}\"/>"}                                    #write svg code for this triangle 
}

  a=233                                               #a,b =coordinate standard values 
  b=377
  z=[0,a,b,a,0]                                       #z coordinates for one face of stellated dodecahedron 
  y=[a,b,0,-b,-a]                                     #y coordinates
  x=[b,0,-a,0,b]                                      #x coordinates
  w=[-b,0,a,0,-b]                                     #alternate  x coordinates

  f[x,y,z,'F0F']                                      #call f
  f[w,y,z,'0F0']                                      #to plot
  f[y,z,x,'00F']                                      #each
  f[y,z,w,'FF0']                                      #face
  f[z,x,y,'F00']                                      #in
  f[z,w,y,'0FF']                                      #turn

  s=File.open("p.svg","w")                            #sort output in o, plot front triangles last
  s.puts'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-450 -450 900 900">',o.sort,'</svg>'
  s.close                                             #add header and footer, and save as svg
}

t=gets.to_i
n=[]
3.times{n<<gets.to_i}
h[t,n]

Produzione

per piccoli dodecaedri stellati (aggiungerà presto alcune immagini degli altri poligoni)

1,0,0,0 posizione iniziale

inserisci qui la descrizione dell'immagine

1,30,0,0 ruotano di 30 gradi verso il basso

inserisci qui la descrizione dell'immagine

1,0,30,0 ruota a destra di 30 gradi (nota: per una vista laterale perfetta, la rotazione sarebbe atan(1/golden ratio)= 31,7 gradi, quindi possiamo ancora vedere un piccolo frammento di blu)

inserisci qui la descrizione dell'immagine

1,0,20,0 ruota a destra di 20 gradi

inserisci qui la descrizione dell'immagine

1,60,10, -63 ruotano verso il basso, a destra e verso l'alto (esempio di orientamento possibile solo con 3 rotazioni)

inserisci qui la descrizione dell'immagine

Dodecaedro normale 0,30,0,0

inserisci qui la descrizione dell'immagine

Dodecaedro grande 2,0,20,0

inserisci qui la descrizione dell'immagine

3,45,45,45 grande dodecaedro stellato inserisci qui la descrizione dell'immagine


3

Mathematica, 426 424 byte

Graphics3D[{Red,Yellow,Green,Cyan,Blue,Magenta}~Riffle~(a=Partition)[Polygon/@Uncompress@"1:eJxtkjEKwkAURNeoySYgeAVP4QFsrcTGTiyUBcEith7A2wgKgpVH8/vgs2TYZmAyw9/5k784XDbHVwihnxisU39N9SiEdI8GO/uWHpXBtjFAgJ7HToFl5WabEdJ+anCqDb6dU9RP65NR59EnI0CZDAWYjFmomBmPCn3/hVVwc9s4xYd66wYqFJVvhMz75vWlHIkhG2HBDJ1V3kYps7z7jG6GomIu/QUJKTGkdtlX2pDM8m6pydyzHIOElBhyG6V9cxulzPldaVJ6lpuUkKUTzWcm+0obkrn0f3OT0rMc0jDkD37nlUo="~a~3~a~5,2],Boxed->1<0]

Utilizza il built-in Graphics3Dper visualizzare la forma. La maggior parte dei byte sono occupati dalle posizioni dei vertici compressi, tuttavia, che vengono quindi Partitioneditati in una forma utilizzabile da Polygon. Finalmente:

Si noti che questa forma può essere ruotata facendo clic e trascinando.


OMG, stavo per eliminare il dodecaedro normale! Per quanto ne so (non conosco o non ho Mathematica) questo è conforme alle regole, quindi +1.
Level River St,

@steveverrill Non penso che cambierebbe troppo la dimensione, ma preferirei non dover riscriverlo da zero.
LegionMammal978,

La tua risposta rimane valida, non ho intenzione di cambiare le regole, sarebbe una cattiva forma. Tuttavia, oltre al bonus di 0,7 per i tre poliedri stellati, ho offerto una taglia per la risposta che può produrre la maggior parte dei quattro poliedri. Se decidessi di aggiornare la tua risposta, immagino che potresti risparmiare molti byte generando le coordinate in modo algoritmico (vedi la sezione informazioni utili della domanda.)
Level River St

@steveverrill, a quanto pare, le posizioni dei vertici coinvolgono le radici dei quartici e non riesco a trovare uno schema.
LegionMammal978,
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.