Dibuja una estrella de Navidad / dodecaedro estrellado

10

Las estrellas de papel son una gran cosa en mi familia en Navidad, así que pensé que una virtual sería genial.

A continuación se muestra una imagen de un dodecaedro regular (de https://en.wikipedia.org/wiki/Dodecahedron , atribuido al autor mencionado allí).

ingrese la descripción de la imagen aquí

El proceso de estelación (wikipedia) cuando se aplica a un poliedro implica extender las caras hasta que crucen otras caras. Comenzando así con el dodecaedro regular, obtenemos las siguientes formas:

Pequeño dodecaedro estrellado, gran dodecaedro y gran dodecaedro estrellado

Imagen de http://jwilson.coe.uga.edu/emat6680fa07/thrash/asn1/stellations.html

ingrese la descripción de la imagen aquí

Estas son las tres posibles Stellations del dodecaedro (Wolfram). Forman una progresión natural desde el dodecaedro hasta el pequeño dodecaedro estrellado, el gran dodecaedro y el gran dodecaedro estrellado, a medida que extendemos las caras cada vez más.

Tarea

Su programa o función debe mostrar o generar en un archivo de imagen uno de los siguientes poliedros: dodecaedro regular, dodecaedro estrellado pequeño, gran dodecaedro o gran dodecaedro estrellado .

El esquema de color debe ser como la segunda imagen de arriba. Cada uno de los seis pares de caras opuestas será uno de los seis colores rojo, amarillo, verde, cian, azul y magenta. Puede usar colores predeterminados con estos nombres en su idioma o en su documentación, o usar los colores FF0000, FFFF00, 00FF00, 00FFFF, 0000FF y FF00FF (puede atenuarlos reduciendo la intensidad a un mínimo del 75% si lo desea, por ejemplo reduciendo las F a C).

Tenga en cuenta que definimos una "cara" como todas las áreas en el mismo plano. Por lo tanto, en las imágenes de arriba la cara frontal es amarilla (y la cara posterior paralela también sería amarilla).

El fondo debe ser negro, gris o blanco. Los bordes pueden omitirse, pero deben ser negros si se dibujan.

Reglas

El poliedro mostrado debe tener entre 500 y 1000 píxeles de ancho (el ancho se define como la distancia máxima entre dos vértices mostrados).

El poliedro visualizado debe estar en proyección en perspectiva (punto de vista al menos a 5 anchos del poliedro), o en proyección ortográfica (efectivamente, una proyección en perspectiva con el punto de vista en el infinito).

El poliedro debe poder visualizarse desde cualquier ángulo. (No es aceptable elegir el ángulo más fácil posible y hacer una forma 2D codificada). El usuario puede especificar el ángulo de cualquiera de las siguientes maneras:

  1. Introducción de tres ángulos correspondientes a tres rotaciones, desde stdin, o como parámetros de función o línea de comando. Estos pueden ser ángulos de Euler (donde las primeras y últimas rotaciones son sobre el mismo eje) o ángulos de Tait-Bryan (donde hay una rotación cada uno sobre los ejes x, y y z) https://en.wikipedia.org/ wiki / Euler_angles (en pocas palabras, todo vale siempre que cada rotación sea sobre el eje x, y o z y las rotaciones consecutivas sean sobre ejes perpendiculares).

  2. Facilidad para que el usuario gire el poliedro en pasos de no más de 10 grados alrededor de los ejes x e y y actualice la pantalla, cualquier número arbitrario de veces (suponiendo que el eje z sea perpendicular a la pantalla).

El poliedro debe ser sólido, no estructura metálica.

No se permiten construcciones para dibujar poliedros (¡te estoy mirando, Mathematica!)

Puntuación

Esto es codegolf. El código más corto en bytes gana.

Bonos

Multiplique su puntaje por 0.5 si no usa los colores incorporados para dibujar en 3D.

Multiplique su puntaje por 0.7 si puede mostrar las tres stellations del dodecaedro, seleccionable por el usuario por un entero 1-3 ingresado desde stdin, o por función o parámetro de línea de comando.

Si elige ambos bonos, su puntaje se multiplicará por 0.5 * 0.7 = 0.35

Información útil (fuentes como abajo)

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

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

El dodecaedro tiene 20 vértices. 8 de ellos forman los vértices de un cubo con las siguientes coordenadas cartesianas (x, y, z):

(± 1, ± 1, ± 1)

Los 12 restantes son los siguientes (phi es la proporción áurea)

(0, ± 1 / φ, ± φ)

(± 1 / φ, ± φ, 0)

(± φ, 0, ± 1 / φ)

El casco convexo del pequeño dodecaedro estrellado y el gran dodecaedro es obviamente un dodecaedro regular. Los vértices exteriores describen un icosaedro.

Según Wikipedia, los 12 vértices de un icosaedro se pueden describir de manera similar a las permutaciones cíclicas de (0, ± 1, ± φ). Los vértices exteriores del pequeño dodecaherón estrellado y el gran dodecaedro (en la misma escala que el dodecaedro anterior) forman un icosaedro más grande, donde las coordenadas de los vértices son permutaciones cíclicas de (0, ± φ ^ 2, ± φ).

Los ángulos entre las caras del dodecaedro y el icosaedro son 2 arctan (phi) y arccos (- (√5) / 3) respectivamente.

Para obtener consejos sobre la rotación, consulte https://en.wikipedia.org/wiki/Rotation_matrix

EDITAR: Por error he permitido el dodecaedro regular, y no puedo retraerlo ahora. La bonificación x0.7 por dibujar los tres poliedros estrellados permanece. El día de Año Nuevo emitiré una recompensa de 100 por la respuesta que puede mostrar la mayor parte de los cuatro poliedros, con el código más corto como el desempate.

Level River St
fuente
@ LegionMammal978 Las incorporaciones para dibujar poliedros (p dodecahedron. Ej. ) No están permitidas. Algunos idiomas tienen facilidades para construir modelos 3D con comandos como triangle[[a,b,c],[p,q,r],[x,y,z]]. Estos lenguajes generalmente tienen incorporados para rotar y mostrar el modelo, cuidando automáticamente de no mostrar caras ocultas, etc. Se permiten soluciones como estas, pero no atraerán la bonificación. El propósito del bono es permitir que los idiomas que no tienen estas instalaciones sean competitivos, y también atraer soluciones más interesantes.
Level River St
@ LegionMammal978 jaja, sabía que Mathematica sería el lenguaje que causaba problemas. Polyhedrondatano está permitido, ya que es claramente una construcción para dibujar poliedros. Si su respuesta no usa los componentes incorporados para dibujar poliedros y cumple con las otras reglas, entonces es aceptable. Su punto parece ser que, dado el hecho de que tiene que colorear las caras correctamente, de Polyhedrondatatodos modos no le ahorraría mucho, por lo que en la práctica puede ser una restricción algo arbitraria. Estoy de acuerdo en cierta medida, pero es más justo para todos si evito cambiar las reglas después de publicar.
Level River St

Respuestas:

3

Python 2.7, 949 bytes

Aquí está la solución para el dodecaedro regular trazado usando matplotlib. El bosquejo del código no golfizado (que no se muestra aquí) se describe a continuación:

  • Hacer vértices Hacer bordes (basado en 3 vecinos más cercanos, módulo scipy.spatial.KDtree)
  • Haga caras basadas en ciclos de gráficos con longitud 5 (módulo networkx)
  • Haga facenormales (y seleccione aquellos con la cara exterior normal, numpy.cross)
  • Generar coloración basada en las normales de la cara.
  • Trazado 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()

ingrese la descripción de la imagen aquí

Willem
fuente
3

Rubí, 784 bytes * 0.5 * 0.7 = 274.4

Mi propia respuesta, por lo tanto, no es elegible para mi recompensa.

Elegible tanto para el bono incorporado no 3D como para el sorteo de todas las bonificaciones de stellations.

->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}

Entrada como parámetros de función

Un entero 0..3 correspondiente al dodecaedro regular, pequeño dodecaedro estrellado, gran dodecaedro estrellado

Una matriz de tres enteros que corresponden a ángulos de grados para rotaciones alrededor de los ejes x, y y x (nuevamente) (ángulos de Euler adecuados, que permiten lograr cualquier rotación).

Salida de un archivo p.svgque se puede mostrar en un navegador web.

Explicación

Las matrices x, y, z en la parte inferior del código contienen las coordenadas de los puntos exteriores de una cara de un pequeño dodecaedro estrellado. Esto puede inscribirse en el icosaedro cuyos 12 vértices están definidos por las permutaciones cíclicas de (+/- 377, + / - 233, + / - 0). Tenga en cuenta que 377 y 233 son números consecutivos de Fibonacci y, por lo tanto, 377/233 es una aproximación excelente a la proporción áurea.

una matriz adicional w contiene las coordenadas x multiplicadas por -1, equivalente a la reflexión en el plano x. La función f se llama 6 veces, una vez para cada color, con las diferentes permutaciones cíclicas de x, y, z y w, y, z.

Las tres rotaciones se pasan como parámetros en n []. para usar sin and cos en Ruby, es necesario hacerlo include Math. Para evitar esto, el coseno y el seno del ángulo se obtienen elevando la raíz cuadrada de -1 "i"a una potencia de (ángulo en grados / 90) Las partes real e imaginaria de este número se almacenan en k (coseno) y l ( seno)

Antes de la rotación, se intercambian los valores x e y. Luego, la multiplicación matricial se aplica a los valores y y z para dar una rotación sobre el eje x. El intercambio de valores permite que las tres rotaciones se realicen en un bucle.

Hasta ahora, solo tenemos un anillo de puntos. Para obtener el resto, necesitamos encontrar el centro del pentágono / estrella. Esto se hace al encontrar el promedio de coordenadas de los 5 vértices, que se almacenan en p, q, r.

Como se mencionó anteriormente, solo se realiza una llamada de función por color. Se prueba el signo de r (el promedio de las coordenadas z y, por lo tanto, la coordenada de la cara). Si es positivo, la cara es frontal y, por lo tanto, visible. Si es negativo, la cara es una cara posterior. Es invisible, y no tenemos función para la cara opuesta. Por lo tanto, las tres coordenadas deben invertirse. El signo de r se almacena en e para facilitar esto.

La cara está construida con 5 triángulos, cuyos vértices son combinaciones lineales de los vértices exteriores del pequeño dodecaedro estrellado y el centro de la cara. En el caso del pequeño dodecaedro estrellado, para las puntas de los triángulos establecemos a = 1 y b = 0 (contribución 1 de x, y, z y 0 de p, q, r). Para los 2 vértices base del triángulo, establecemos c = -0.382 (contribución 1 / proporción áurea ^ 2 de x, y, z) yd = 1.382 (contribución de p, q, r.) La razón de la contribución negativa es que los vértices base del triángulo se definen en términos de las puntas opuestas, que están en el lado opuesto de la cara. Las coordenadas obtenidas se multiplican por e según sea necesario.

Las cuatro matrices sin nombre cuyos valores se asignan para a,b,c,dcontener los valores requeridos para el dodecaedro regular, el pequeño dodecaedro estrellado, el gran dodecaedro y el gran dodecaedro estrellado, seleccionados según la variable tTenga en cuenta que para el pequeño dodecaedro estrellado y el gran dodecaedro, a + b = c + d = 1. La relación a + b = c + d se aplica a las otras formas, pero se aplica una escala diferente.

Se crea una línea de código svg para cada triángulo. Contiene una ID derivada de la suma de las coordenadas z de los 3 vértices del triángulo, una descripción de los vértices de las tres coordenadas del triángulo y un color. tenga en cuenta que vemos directamente hacia abajo el eje z en proyección ortográfica. Así, 2D x = 3D x y 2D y = 3D y. La línea se agrega ah.

finalmente, después de finalizar todas las llamadas a funciones, h se ordena de modo que los triángulos del valor z más alto (al frente) se tracen en último lugar, y todo se guarda como un archivo svg con el texto de encabezado y pie de página apropiado.

Sin golf en el programa de prueba

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]

Salida

para dodecaedro estrellado pequeño (pronto agregará algunas imágenes de los otros polígonos)

1,0,0,0 posición de inicio

ingrese la descripción de la imagen aquí

1,30,0,0 rotar 30 grados hacia abajo

ingrese la descripción de la imagen aquí

1,0,30,0 gira a la derecha 30 grados (nota: para una vista lateral perfecta, la rotación sería atan(1/golden ratio)= 31.7 grados, por lo tanto, todavía podemos ver una pequeña franja azul)

ingrese la descripción de la imagen aquí

1,0,20,0 girar a la derecha 20 grados

ingrese la descripción de la imagen aquí

1,60,10, -63 rotar hacia abajo, hacia la derecha y hacia arriba (ejemplo de orientación solo es posible con 3 rotaciones)

ingrese la descripción de la imagen aquí

0,30,0,0 dodecaedro regular

ingrese la descripción de la imagen aquí

2,0,20,0 gran dodecaedro

ingrese la descripción de la imagen aquí

3,45,45,45 gran dodecaedro estrellado ingrese la descripción de la imagen aquí

Level River St
fuente
3

Mathematica, 426 424 bytes

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]

Utiliza el incorporado Graphics3Dpara mostrar la forma. Sin embargo, la mayoría de los bytes son ocupados por las ubicaciones de vértices comprimidas, que luego se Partitioneditan en una forma que puede utilizar Polygon. Finalmente:

Tenga en cuenta que esta forma se puede girar haciendo clic y arrastrando.

LegionMammal978
fuente
¡Dios mío, iba a eliminar dodecaedro regular! Por lo que puedo decir (no sé o tengo Mathematica) esto cumple con las reglas, entonces +1.
Level River St
@steveverrill No creo que cambie demasiado el tamaño, pero preferiría no tener que volver a escribir esto desde cero.
LegionMammal978
Su respuesta sigue siendo válida, no voy a cambiar las reglas, sería una mala forma. Sin embargo, además de la bonificación 0.7 para los tres poliedros estrellados, he ofrecido una recompensa por la respuesta que puede producir la mayor parte de los cuatro poliedros. Si decidió actualizar su respuesta, creo que podría ahorrar muchos bytes generando las coordenadas algorítmicamente (consulte la sección de información útil de la pregunta).
Level River St
@steveverrill, lo haría, pero aparentemente, las ubicaciones de los vértices involucran las raíces de los cuartos, y no puedo encontrar un patrón.
LegionMammal978