Code for cover artwork
Here is the code used to generate the tessellated pattern used on the cover of this book. It’s written in Python, and makes use of the DrawSVG package. It’s included here because it’s a concise example of a complete Python program which includes docstrings (module and function), imported Python modules, an imported third-party module, constants, functions and functional decomposition, and driver code. This is all written in conformance to PEP 8 (or as close as I could manage with the constraint of formatting for book page).
"""
Cover background for ITPACS.
Clayton Cafiero <cbcafier@uvm.edu>
Requires DrawSVG package.
To install DrawSVG: `$ pip install "drawsvg[raster]~=2.2"`
See: https://pypi.org/project/drawsvg/
DrawSVG requires Cairo on host system.
Ubuntu: `$ sudo apt install libcairo2`
macOS: `$ brew install cairo`
Anaconda: `$ conda install -c anaconda cairo`
See: https://www.cairographics.org/
For info on SVG 2: https://svgwg.org/svg2-draft/
"""
import math # 'cause we need a little trig
import drawsvg as draw
# A lovely selection of named SVG colors.
= ['tomato', 'salmon', 'lightsalmon', 'coral',
COLORS 'orangered', 'sandybrown', 'orange']
= 40 # Everything is derived from this...
TRAPEZOID_LEG = math.sin(math.radians(60)) * TRAPEZOID_LEG
TRAPEZOID_HEIGHT = TRAPEZOID_LEG / 2
TRAPEZOID_BASE_SEGMENT = TRAPEZOID_LEG + 2 * TRAPEZOID_BASE_SEGMENT
TRAPEZOID_BASE = TRAPEZOID_LEG * math.sqrt(3)
TILE_HEIGHT # Taking overlap into consideration we tile @ 120 x 105
= math.ceil(1950 / 120) + 2
COLS = math.ceil(2850 / 105) + 2
ROWS
def draw_tile(rotate, fill):
"""If we choose the right starting point for drawing the tile,
and rotate about that point, we don't have to worry about x, y
translation. """
= f'rotate({rotate}, 0, 0)' # angle, center_x, center_y
transform return draw.Lines(0, 0,
0,
TRAPEZOID_BASE, + TRAPEZOID_LEG,
TRAPEZOID_BASE_SEGMENT
TRAPEZOID_HEIGHT,
TRAPEZOID_BASE_SEGMENT, TRAPEZOID_HEIGHT,0, TILE_HEIGHT,
-TRAPEZOID_LEG, TILE_HEIGHT,
=True, stroke_width=0.5,
close='gray', fill=fill,
stroke=1.0, transform=transform)
fill_opacity
def draw_cube(trans_x, trans_y, colors_):
"""Assemble a cube from three rotated tiles. """
= f'translate({trans_x}, {trans_y})'
transform = draw.Group(fill='none', stroke='black',
c =transform)
transform0, colors_[0]))
c.append(draw_tile(120, colors_[1]))
c.append(draw_tile(240, colors_[2]))
c.append(draw_tile(return c
if __name__ == '__main__':
= draw.Drawing(1950, 2850, origin=(0, 0))
d = 0.0
translate_y
for i in range(ROWS):
if i % 2:
= 0.0
translate_x else:
= TRAPEZOID_BASE_SEGMENT + TRAPEZOID_LEG
translate_x for j in range(COLS):
# rotate colors
= [COLORS[(i + j) % len(COLORS)],
colors + j + 4) % len(COLORS)],
COLORS[(i + j + 8) % len(COLORS)]]
COLORS[(i
d.append(draw_cube(translate_x, translate_y, colors))+= TRAPEZOID_BASE + TRAPEZOID_LEG
translate_x += TILE_HEIGHT + TRAPEZOID_HEIGHT
translate_y
1.0) # Set number of pixels per geometry unit
d.set_pixel_scale('cover.svg')
d.save_svg('cover.png') d.save_png(