Last active
March 4, 2021 01:28
-
-
Save louisswarren/29aeab8028cd97444475314cf394b421 to your computer and use it in GitHub Desktop.
Svg files from python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
import sys | |
from svg import * | |
def log(*a, **k): | |
print(*a, **k, file=sys.stderr) | |
ROWS = 64 | |
COLS = ROWS*2-1 | |
BOXSIZE = 10 | |
IMG_HEIGHT = 2000 | |
IMG_WIDTH = IMG_HEIGHT / (ROWS * BOXSIZE + 1) * (COLS * BOXSIZE + 1) | |
# Basic header | |
svg_header() | |
svg_open(width=IMG_WIDTH, height=IMG_HEIGHT, | |
x_bias=-BOXSIZE*COLS/2, y_bias=-1, | |
xw=COLS*BOXSIZE+2, yh=ROWS*BOXSIZE+2) | |
def draw_cell(row, col, value=None): | |
fill = "grey" if value else "white" | |
svg_rect((BOXSIZE*(col-0.5), BOXSIZE*row), BOXSIZE, BOXSIZE, | |
fill=fill, stroke="black") | |
if len(sys.argv) > 1: | |
rule = int(sys.argv[1]) | |
else: | |
rule = 30 | |
cells = defaultdict(lambda: False) | |
cells[(0,0)] = True | |
draw_cell(0, 0, cells[(0,0)]) | |
for j in range(1, ROWS): | |
for i in range(-j, j+1): | |
prev = 4 * cells[(j-1, i-1)] | |
prev += 2 * cells[(j-1, i )] | |
prev += 1 * cells[(j-1, i+1)] | |
cells[(j,i)] = rule & (1 << prev) != 0 | |
draw_cell(j, i, cells[(j,i)]) | |
# Footer | |
svg_close() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
n = 24 | |
$(n).mp4: stringart.py | |
$(MAKE) -j 4 $$(for i in $$(seq -w 1 $n); do echo -n "$n-$$i.png "; done) | |
ffmpeg -r 2 -f image2 -s 800x800 -i $(n)-%02d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p $@ | |
%.png: %.svg | |
convert $^ $@ | |
$(n)-%.svg: stringart.py | |
python3 $^ $(n) $* > $@ | |
$(n).svg: stringart.py | |
python3 $^ > $@ | |
.PHONY: clean | |
clean: | |
rm -f *.png *.svg *.mp4 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
import sys | |
from svg import * | |
def log(*a, **k): | |
print(*a, **k, file=sys.stderr) | |
def point_to_tick(point, s): | |
p1 = (point[0] * (1+s), point[1] * (1+s)) | |
p2 = (point[0] * (1-s), point[1] * (1-s)) | |
return p1, p2 | |
def circle(n, s=1, r=1): | |
for i in range(0, n+1): | |
t = 2 * math.pi * i * s / n | |
yield r*math.sin(-t), -r*math.cos(t) | |
if len(sys.argv) >= 2: | |
ticks = int(sys.argv[1]) | |
else: | |
ticks = 24 | |
# Basic header | |
svg_header() | |
svg_open(width=800, height=800, x_bias=-110, y_bias=-110, xw=220, yh=220) | |
# Outer circle | |
svg_circle((0, 0), 100, fill='none', stroke='black') | |
# Tick marks | |
for point in circle(ticks, r=100): | |
print(svg_line(*point_to_tick(point, 0.03), stroke='black')) | |
if len(sys.argv) >= 3: | |
circ = tuple(circle(ticks, int(sys.argv[2]), 100)) | |
svg_poly(*circ[1:], stroke='red', fill='none') | |
svg_line(*circ[:2], stroke='blue') | |
else: | |
# Draw all non-generating cycles | |
for k in range(2, ticks, 2): | |
for j in range(2, k+1): | |
if (ticks % j) == (k % j) == 0: | |
svg_poly(*circle(ticks, k, 100), stroke='red', fill='none') | |
log(k) | |
break | |
# Footer | |
svg_close() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def xml(tag, _xml_tag_is_a_singleton=True, **options): | |
s = f'<{tag}' | |
kw_attrib = lambda x: x.replace('_', '-') | |
if options: | |
s += ' ' | |
s += ' '.join(f'{kw_attrib(k)}="{str(v)}"' for k, v in options.items()) | |
if _xml_tag_is_a_singleton: | |
s += ' />' | |
else: | |
s += '>' | |
print(s) | |
def xml_open(*args, **kwargs): | |
xml(*args, **kwargs, _xml_tag_is_a_singleton=False) | |
def xml_close(tag): | |
print(f'</{tag}>') | |
def svg_header(): | |
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>' | |
def svg_open(width, height, x_bias, y_bias, xw, yh): | |
vb = f'{x_bias} {y_bias} {xw} {yh}' | |
ns = 'http://www.w3.org/2000/svg' | |
xml_open('svg', width=width, height=height, viewBox=vb, xmlns=ns) | |
def svg_close(): | |
xml_close('svg') | |
def svg_poly(*points, **opts): | |
point_str = ' '.join(f'{x},{y}' for x, y in points) | |
xml('polyline', points=point_str, **opts) | |
def svg_circle(point, radius, **opts): | |
xml('circle', cx=point[0], cy=point[1], r=radius, **opts) | |
def svg_line(p1, p2, **opts): | |
xml('line', x1=p1[0], y1=p1[1], x2=p2[0], y2=p2[1], **opts) | |
def svg_rect(p, width, height, x_radius=0, y_radius=0, **opts): | |
xml('rect', x=p[0], y=p[1], width=width, height=height, | |
rx=x_radius, ry=y_radius, **opts) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment