画一个圣诞星/星状十二面体


10

在圣诞节,纸星星是我家庭中的一件大事,所以我认为虚拟的星星会很酷。

下面是常规十二面体的图像(来自https://en.wikipedia.org/wiki/Dodecahedron,归因于此处提到的作者。)

在此处输入图片说明

当应用于多面体时,星状过程(维基百科)涉及到扩展这些面直到它们与其他面交叉。因此,从常规十二面体开始,我们获得以下形状:

小星状十二面体,大十二面体和大星状十二面体

图片来自http://jwilson.coe.uga.edu/emat6680fa07/thrash/asn1/stellations.html

在此处输入图片说明

这是十二面体(Wolfram)的三个可能的星状。当我们将面孔延伸得越来越远时,它们从十二面体自然过渡到小型星状十二面体,大十二面体和大星状十二面体。

任务

您的程序或函数应显示以下多面体之一或将其输出到图像文件:常规十二面体,小星状十二面体,大十二面体或大星状十二面体

配色方案应为上面的第二张图像。六对相对的面中的每一个均应为红色,黄色,绿色,青色,蓝色和洋红色六种颜色之一。您可以在您的语言或其文档中使用带有这些名称的默认颜色,也可以使用FF0000,FFFF00、00FF00、00FFFF,0000FF和FF00FF的颜色(如果需要,可以通过将强度降低到至少75%来降低这些颜色,例如将F减为C。)

请注意,我们将“面”定义为同一平面上的所有区域。因此,在上面的图像中,正面为黄色(平行的背面也将为黄色)。

背景应为黑色,灰色或白色。边缘可以省略,但如果绘制则应为黑色。

规则

显示的多面体的宽度必须在500到1000像素之间(宽度定义为任意两个显示的顶点之间的最大距离。)

显示的多面体必须是透视投影(视点距离多面体至少5个宽度)或正射投影(实际上是视点在无穷远处的透视投影)。

多面体必须可以从任何角度显示。(选择最简单的角度并制作硬编码的2D形状是不可接受的。)用户可以通过以下两种方式指定角度:

  1. 从标准输入或作为函数或命令行参数输入对应于三个旋转的三个角度。这些角度可以是欧拉角(第一个和最后一个旋转都围绕同一轴)或泰特布赖恩角(其中每个绕x,y和z轴旋转一个角度)https://en.wikipedia.org/ wiki / Euler_angles(简单地说,只要每次旋转均围绕x,y或z轴且连续旋转均围绕垂直轴,任何事情都会发生。)

  2. 用户可以任意多倍地绕x和y轴旋转多面体10步,并刷新显示(假定z轴垂直于屏幕)。

多面体必须是实体,而不是线框。

不允许用于绘制多面体的内置函数(我在看着你,Mathematica!)

计分

这是代码高尔夫。以字节为单位的最短代码获胜。

奖金

如果您不将内置函数用于3D绘图,则将您的分数乘以0.5。

如果可以显示十二面体的所有三个星号,则将分数乘以0.7,用户可以通过从stdin输入的整数1-3或函数或命令行参数来选择十二面体。

如果您同时获得这两个奖金,您的分数将乘以0.5 * 0.7 = 0.35

有用的信息(来源如下)

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

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

十二面体有20个顶点。它们中的8个形成具有以下笛卡尔(x,y,z)坐标的立方体的顶点:

(±1,±1,±1)

其余的12个如下(phi是黄金比例)

(0,±1 /φ,±φ)

(±1 /φ,±φ,0)

(±φ,0,±1 /φ)

小星状十二面体和大十二面体的凸包显然是规则的十二面体。外部顶点描述一个二十面体。

根据维基百科,可以以与(0,±1,±φ)的循环置换类似的方式描述二十面体的12个顶点。小星状十二面体和大十二面体的外部顶点(与上面的十二面体的比例相同)形成一个较大的二十面体,其中顶点的坐标是(0,±φ^ 2,±φ)的循环排列。

十二面体和二十面体的面之间的角度分别为2 arctan(phi)和arccos(-(√5)/ 3)。

有关旋转的提示,请参见https://en.wikipedia.org/wiki/Rotation_matrix

编辑:由于错误,我已经允许使用常规十二面体,并且现在无法收回它。绘制所有三个星状多面体的x0.7奖励仍然存在。在元旦那天,我将悬赏100英镑,以显示最多四个多面体中的大多数,并以最短的代码作为抢七。


dodecahedron不允许使用@ LegionMammal978内建绘图多面体(例如)。某些语言具有使用命令构建3D模型的功能triangle[[a,b,c],[p,q,r],[x,y,z]]。这些语言通常具有用于旋转和显示模型的内建函数,自动注意不显示隐藏的面孔等。允许使用此类解决方案,但不会吸引人。奖励的目的是使不具备这些功能的语言具有竞争力,并吸引更多有趣的解决方案。
水平河圣

@ LegionMammal978哈哈,我知道Mathematica是会引起问题的语言。Polyhedrondata不允许使用,因为它显然是绘制多面体的内置函数。如果您的答案不使用内置函数绘制多面体,并且符合其他规则,则可以接受。您的观点似乎是,鉴于您必须正确着色脸部的事实,Polyhedrondata无论如何都不会为您节省很多,因此实际上这可能是一个任意的限制。我在一定程度上表示同意,但是如果我避免在发布后更改规则,那对所有人来说都是公平的。
水平河圣

Answers:


3

Python 2.7,949字节

这是使用matplotlib绘制的常规十二面体的解决方案。未概述代码的粗略轮廓(此处未显示)概述如下:

  • 制作顶点制作边缘(基于3个最近的邻居,模块scipy.spatial.KDtree)
  • 根据长度为5的图形循环制作面(模块networkx)
  • 制作面法线(并选择面法线为numpy.cross的法线)
  • 根据脸部法线生成着色
  • 使用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()

在此处输入图片说明


3

Ruby,784个字节* 0.5 * 0.7 = 274.4

我自己的回答,因此没有资格获得我的赏金。

既有资格获得非3D内置奖金,也有资格获得所有星状奖励。

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

输入为功能参数

整数0..3,对应于常规十二面体,小星状十二面体,大星状十二面体

三个整数数组,分别对应于围绕x,y和x(再次)轴旋转的度角(适当的Euler角,可以实现任何旋转)。

输出p.svg可以在Web浏览器中显示 的文件。

说明

代码底部的数组x,y,z包含一个小的星状十二面体的一个面的外点的坐标。可以在二十面体中进行刻写,其十二个顶点由(+/- 377,+ /-233,+ /-0)的循环排列定义。请注意,377和233是连续的斐波那契数,因此377/233是黄金比率的极佳近似值。

另一个数组w包含x坐标乘以-1的值,等效于x平面中的反射。函数f被调用6次,每种颜色一次,分别具有x,y,z和w,y,z的不同循环排列。

三个旋转作为参数传递给n []。要在Ruby中使用sin和cos,必须这样做include Math。为避免这种情况,通过将-1的平方根提高"i"到(角度度数/ 90)的幂来获得角度的余弦和正弦值。此数的实部和虚部分别存储在k(余弦)和l(正弦

旋转之前,将交换x和y值。然后将矩阵乘法应用于y和z值,以绕x轴旋转。值的交换使三个旋转可以循环执行。

到目前为止,我们只有一环。要获得其余部分,我们需要找到五角形/星形的中心。这是通过找到存储在p,q,r中的5个顶点的坐标的平均值来完成的。

如前所述,每种颜色只能进行一次函数调用。测试了r的符号(z坐标的平均值,因此是面部的坐标)。如果为正,则该面为正面,因此可见。如果为负,则该面为背面。它是不可见的,并且我们没有函数调用相反的面孔。因此,所有三个坐标都必须反转。r的符号存储在e中以方便执行此操作。

面由5个三角形构成,其顶点是小星状十二面体的外部顶点和面中心的线性组合。对于小星状十二面体,对于三角形的尖端,我们设置a = 1和b = 0(x,y,z贡献1,p,q,r贡献0)。对于三角形的2个基本顶点,我们将c = -0.382(来自x,y,z的贡献1 /黄金比例^ 2)和d = 1.382(来自p,q,r的贡献)设置为。三角形的基本顶点是根据相对的尖端(位于面的相对侧)定义的。必要时将获得的坐标乘以e。

四个未命名的数组,其值被分配为a,b,c,d包含常规十二面体,小星状十二面体,大十二面体和大星状十二面体的必需值,并根据变量进行选择。t请注意,对于小星状十二面体和大十二面体,a + b = c + d = 1。关系a + b = c + d适用于其他形状,但比例不同。

为每个三角形创建一行svg代码。它包含一个ID,该ID是从三角形的三个顶点的z坐标的总和,三角形的三个坐标的顶点的描述以及颜色得出的。请注意,我们以正交投影的方式垂直向下查看z轴。因此,2D x = 3D x和2D y = 3D y。该行已添加到h.

最后,在所有函数调用完成后,对h进行排序,以便最后绘制z值最高的三角形(在前面),然后将整个内容另存为带有相应页眉和页脚文本的svg文件。

取消测试程序

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]

输出量

用于小型星状十二面体(将很快添加其他多边形的一些图像)

1,0,0,0原位

在此处输入图片说明

1,30,0,0向下旋转30度

在此处输入图片说明

1,0,30,0向右旋转30度(注意:对于完美的侧视图,旋转将为atan(1/golden ratio)= 31.7度,因此我们仍然可以看到一小段蓝色)

在此处输入图片说明

1,0,20,0向右旋转20度

在此处输入图片说明

1,60,10,-63上下左右旋转(方向示例仅可旋转3圈)

在此处输入图片说明

0,30,0,0常规十二面体

在此处输入图片说明

2,0,20,0大十二面体

在此处输入图片说明

3,45,45,45大星状十二面体 在此处输入图片说明


3

Mathematica,426 424字节

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]

使用内置的Graphics3D显示形状。但是,大多数字节都由压缩的顶点位置占据,然后将其Partition编辑成可用于的形式Polygon。最后:

请注意,可以通过单击和拖动来旋转此形状。


天哪,我要删除常规的十二面体!据我所知(我不知道或没有Mathematica),这符合规则,所以+1。
水平河圣

@steveverrill我不认为它会改变太大的大小,但我希望不必从头开始重写它。
LegionMammal978

您的答案仍然有效,我不会更改规则,这将是错误的形式。但是,除了三个星状多面体的0.7奖金外,我还提供了赏金,以使答案可以产生四个多面体中的大部分。如果您确实决定更新答案,我认为您可以通过算法生成坐标来节省很多字节(请参阅问题的有用信息部分。)
Level River St

@steveverrill,但是,显然,顶点位置涉及四次方的根,而我找不到模式。
LegionMammal978
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.