垫片编织-画一个Sierpiński结


33

给定一个整数N> = 2,产生一个图像,该图像显示度数为N的Sierpiński结。

例如,以下是2、3、4和5级的结:

学位2 学位3 学位4 5级

单击图像以查看完整尺寸(度数越高,图像越大)。

规格

  1. 使用N度的Sierpiński三角形的顶点作为引导点绘制N度的Sierpiński结。N度的Sierpiński三角形是排列成较大三角形的三个N-1度的Sierpiński三角形。0度的Sierpiński三角形是等边三角形。
  2. 最小的三角形组成部分的边长为64,这使Sierpiński三角形的结长以 64 * 2 ^ N
  3. 外部三角形的中心位于图像的中心。这在顶部和底部没有相等的空格。
  4. 输出是边长为的正方形图像,天花板(64 * 2 ^ N * 2 / ROOT3)其中天花板(x)ceiling(x),大于或等于x的最小整数。当三角形的中心位于图像的中心时,此大小足够大,足以将基础Sierpiński三角形的顶部顶点包含在图像中。
  5. 单个曲线必须在其上方和下方通过,并严格交替。解决方案可以在上下限之间选择,也可以在上下限之间选择。
  6. 示例图像显示黑色前景和白色背景。您可以选择任何两种容易区分的颜色。允许抗锯齿,但不是必需的。
  7. 在两个圆弧相交处或曲线在其自身上方或下方通过的地方一定不能有间隙。
  8. 输出可以是任何光栅格式的图像文件,也可以是包含正确的默认显示尺寸的任何矢量格式的图像文件。如果直接在屏幕上显示,则必须采用一种允许滚动的形式,以便在大于屏幕时查看完整图像。

确定圆弧中心,半径和厚度

  1. 结由一系列圆弧构成,这些圆弧在切线平行的点相交,从而实现无缝连接。这些弧显示为环形扇形(具有厚度的弧)。
  2. 这些弧的中心是最小的倒置三角形的顶点。每个这样的顶点都是一个弧的中心。
  3. 每个弧的半径为 64 *根3/2
  4. 唯一的例外是,三个最外面的三角形(在大三角形的拐角处)的弧线的中心是两个相邻内部顶点的中点,因此半径为 64 *(ROOT3 / 2-1 / 2)
  5. 每个圆弧的总厚度(内半径和外半径之差)为,64 *(ROOT3 / 2)/ 4并且其黑色边框的厚度均为64 *(ROOT3 / 2)/ 16。曲线必须具有这些边框,而不仅仅是实心条。

计量单位

  1. 所有距离均以像素为单位(1是2个相邻像素之间的水平或垂直距离)。
  2. 3的平方根必须精确到7个有效数字。也就是说,您的计算必须等同于使用ROOT3,这样1.7320505 <= ROOT3 < 1.7320515

计分

以字节为单位的最短代码获胜。


对于那些想知道的人,不包括N = 0和N = 1,因为它们对应于一个圆和一个三叶形,这与适用于N> = 2的模式不太匹配。我希望应对这种挑战的大多数方法都需要为0和1添加特殊情况代码,因此我决定省略它们。


1
有一个图表来显示所有数字都对您有帮助吗?
trichoplax

在打高尔夫球之前,我需要7个有效数字来表示细小的细节,例如线条的粗细等?像“ 7个有效数字或1个像素,以较大者为准”这样的精度似乎更合适。
级圣河在

@LevelRiverSt,因为图像的大小随输入缩放,即使对于较大的N来说,即使7个有效数字也不足以达到1像素的精度。我在聊天中进行了一些讨论之后确定了7个有效数字,因此所有答案都保持不变标准。
trichoplax

是的,对于较大的N,有必要对图片进行缩放。1000000 x 1000000图像上的7个有效数字对应于0.1像素,但是如果进行中间计算,结果可能会更糟。我只是认为stroke-width:3.464102,如果要获得1像素的精度,类似的东西就有点过分了。如果可以的话,我将继续将其包括在内。
水平河圣

Answers:


27

红宝石,1168 932

改正了昨晚的错误,澄清后需要做更多的高尔夫球运动。

(当前)这是一个完整程序,可以从stdin接受数字并将其输出svg到stdout。我选择svg是因为我知道可以满足问题的所有要求,但是确实存在一些问题。特别是SVG仅支持将圆弧作为path对象的一部分,而不是根据圆心定义两个圆弧。

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

输出N = 4

通过堆栈交换重新缩放。看起来比原来好多了。

在此处输入图片说明 说明

起初,我考虑过类似http://euler.nmt.edu/~jstarret/sierpinski.html的东西,其中三角形分成三个不同颜色的线,每条线形成从一个角到另一个角的路径。不完整的圆圈在此处显示为不完整的六边形。在六边形内刻圆,表明圆半径应为边长sqrt(3)/2的倍数。可以如图所示递归地构造这些股线,但是由于需要对角进行倒圆并且很难知道要沿哪个方向弯曲,因此增加了复杂性,因此我没有使用这种方法。

我所做的是以下几点。

在下图中,您可以看到以Sierpinski三角形排列的属于N = 2单位的水平扭曲(绿色)和其他桥接扭曲(蓝色)。

众所周知,帕斯卡三角形上的奇数形成一个Sierpinski三角形。可以以类似的方式通过从数字开始并用p=1x对其进行异或来获得二进制的sierpinski三角形p<<1

我修改了此方法,从开始并p=2与进行迭代异或p*4。这给出了一个Sierpinski三角形与零列交替。

现在我们可以右移p并使用来检查最后三个位%8。如果是010这样,我们需要绘制一个绿色扭曲,该扭曲属于N = 2单位。如果是的话,101我们需要画一个蓝色的桥梁。为了一起测试这两个数字,我们找到了模%3,如果为2,则需要绘制扭曲。

最后,除了水平扭曲之外,我们还制作了两个分别旋转120度和240度的副本以绘制对角扭曲并完成图片。剩下的就是增加角落。

注释代码

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

在此处输入图片说明


在您说“看起来比原始照片好得多”的地方,可能值得为那些没有意识到的人添加诸如“(单击图像以查看完整尺寸)”之类的内容。
trichoplax

@trichoplax对我而言,单击图像并没有发生。但是无论如何,这是一个PNG,因为堆栈交换不接受svg图像,所以边缘被故意模糊了。我的本地SVG文件边缘更清晰,看起来也更好。
水平河圣

@trichoplax快速修复图像大小。会再打高尔夫。

1
+1出色的工作。我特别喜欢带有彩色编码图的详细说明。
trichoplax

1
超链接已死。
mbomb007 '16
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.