Skip to content

Instantly share code, notes, and snippets.

@justvanrossum
Last active March 18, 2026 20:14
Show Gist options
  • Select an option

  • Save justvanrossum/0e021f873b9f657dcaa6b8d8f06f68e7 to your computer and use it in GitHub Desktop.

Select an option

Save justvanrossum/0e021f873b9f657dcaa6b8d8f06f68e7 to your computer and use it in GitHub Desktop.
A DrawBot script to generate an animation showing that Delaunay triangulation is not affine-invariant
import math
import drawBot as db
from random import random, randint, seed
from fontTools.misc.transform import Transform
from scipy.spatial import Delaunay
def circle(pt, r):
x, y = pt
d = r * 2
db.oval(x - r, y - r, d, d)
def centerScale(sx, sy):
cx = canvasWidth / 2
cy = canvasHeight / 2
t = Transform().translate(cx, cy)
t = t.scale(sx, sy)
return t.translate(-cx, -cy)
rSeed = 5
canvasWidth = 800
canvasHeight = 800
margin = 50
numFrames = 180
repeat = 3
numPoints = 18
seed(rSeed)
basePoints = [
(randint(margin, canvasWidth - margin), randint(margin, canvasHeight - margin))
for i in range(numPoints)
]
for frame in range(numFrames * repeat):
t = frame / numFrames
f = (1 + math.sin(t * 2 * math.pi)) / 2
hScale = 0.15 + 0.85 * f
db.newPage(canvasWidth, canvasHeight)
db.frameDuration(1 / 30)
db.fill(1)
db.rect(0, 0, canvasWidth, canvasHeight)
db.fill(None)
db.stroke(0)
db.lineJoin("round")
db.strokeWidth(3)
tr = centerScale(hScale, 1)
points = [tr.transformPoint(pt) for pt in basePoints]
dln = Delaunay(points)
edgeIndices = set()
for simplex in dln.simplices:
for i in range(3):
edgeIndices.add((simplex[i - 1], simplex[i]))
for i, j in edgeIndices:
db.line(points[i], points[j])
db.fill(0)
db.stroke(None)
for pt in points:
circle(pt, 10)
db.saveImage("delaunay.mp4")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment