博士家园

发表于 2016-11-13 14:50:59 | 显示全部楼层 |阅读模式
Penrose 铺砌是我学 Asymptote 的时候正儿八经画的第一个图。现在用 Python 重新做了一个:





但是方法不同了:这些图是根据 de Bruijn 1981 年的论文 Algebraic theory of Penrose's non-periodic tilings of the plane 绘制的。

Penrose 铺砌可以通过将一个 5 维空间中的格点的一部分投影到某个 2 维平面上得到,或者等价地用 pentagrid 的方法生成。

网上各种版本的代码基本都是 deflation - inflation 方法得到的,这个方法仅能绘制严格意义上的 Penrose 铺砌。代数方法可以绘制所有的(广义)的 Penrose 铺砌。


gif 动态图里显示的就是随机参数生成的不同的图案,它们是互不同构的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2016-11-13 14:51:46 | 显示全部楼层
代码如下:
  1. '''
  2. Draw generalized Penrose tilings using de Bruijn's pentagrid methond.
  3. Reference:
  4. "Algebraic theory of Penrose's non-periodic tilings of the plane", N.G. de Bruijn.
  5. '''

  6. from itertools import combinations, product
  7. import numpy as np
  8. import cairo



  9. GRIDS = [np.exp(2j * np.pi * i / 5) for i in range(5)]

  10. # five real numbers defining the shift in each direction
  11. SHIFT = np.random.random(5)

  12. THIN_RHOMBUS_COLOR = np.random.random(3)
  13. FAT_RHOMBUS_COLOR = np.random.random(3)
  14. EDGE_COLOR = (0.5, 0.5, 0.5)


  15. def rhombus(r, s, kr, ks):
  16.     '''
  17.     Compute the four vertices and color of the rhombus corresponding to
  18.     the intersection point of two grid lines.
  19.     Here 0 <= r < s <= 4 indicate the two grids and ks, kr are integers.
  20.     The intersection point is the solution to a 2x2 linear equation:
  21.     Re[z/GRIDS[r]] + SHIFT[r] = kr
  22.     Re[z/GRIDS[s]] + SHIFT[s] = ks
  23.     '''

  24.     # if s-r = 1 or 4 then this is a thin rhombus, or it's fat if s-r = 2 or 3.
  25.     if (s - r)**2 % 5 == 1:
  26.         color = THIN_RHOMBUS_COLOR
  27.     else:
  28.         color = FAT_RHOMBUS_COLOR

  29.     # the intersection point
  30.     point = (GRIDS[r] * (ks - SHIFT[s])
  31.              - GRIDS[s] * (kr - SHIFT[r])) *1j / GRIDS[s-r].imag

  32.     # 5 integers that indicate the intersection point's position:
  33.     # the i-th integer n_i indicates that this point lies in the n_i-th strip
  34.     # in the i-th grid.
  35.     index = [np.ceil((point/grid).real + shift)
  36.              for grid, shift in zip(GRIDS, SHIFT)]

  37.     # Note the float accuracy problem here:
  38.     # Mathematically the r-th and s-th item of index should be kr and ks,
  39.     # but programmingly it might not.
  40.     # So we have to manully set them to bbe the correct values.
  41.     vertices = []
  42.     for index[r], index[s] in [(kr, ks), (kr+1, ks), (kr+1, ks+1), (kr, ks+1)]:
  43.         vertices.append(np.dot(index, GRIDS))

  44.     return vertices, color


  45. def tile(num_lines):
  46.     '''
  47.     Compute all rhombus lie in a given number of grid lines
  48.     '''
  49.     for r, s in combinations(range(5), 2):
  50.         for kr, ks in product(range(-num_lines, num_lines+1), repeat=2):
  51.             yield rhombus(r, s, kr, ks)


  52. def render(imgsize, num_lines):
  53.     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, imgsize, imgsize)
  54.     ctx = cairo.Context(surface)
  55.     ctx.scale(imgsize/(2.0*num_lines), imgsize/(2.0*num_lines))
  56.     ctx.translate(num_lines, num_lines)
  57.     ctx.set_line_join(2)
  58.     ctx.set_line_width(0.1)

  59.     for rhombus, color in tile(num_lines):
  60.         A, B, C, D = rhombus
  61.         ctx.move_to(A.real, A.imag)
  62.         ctx.line_to(B.real, B.imag)
  63.         ctx.line_to(C.real, C.imag)
  64.         ctx.line_to(D.real, D.imag)
  65.         ctx.line_to(A.real, A.imag)
  66.         ctx.set_source_rgb(*color)
  67.         ctx.fill_preserve()
  68.         ctx.set_source_rgb(*EDGE_COLOR)
  69.         ctx.stroke()

  70.     surface.write_to_png('penrose.png')


  71. if __name__ == '__main__':
  72. render(imgsize=800, num_lines=20)
复制代码

关于我们|手机版|博士家园 ( 沪ICP备15045866号 )(沪公网安备沪公网安备 31011702001868号) 

GMT+8, 2018-10-16 09:17 , Processed in 1.125000 second(s), 16 queries , Gzip On.

Powered by Discuz! X3.2

© 2004-2018 Comsenz Inc.

快速回复 返回顶部 返回列表