#! /usr/bin/python3 # Last edited on 2026-03-25 04:27:28 by stolfi import os, sys, re from sys import stderr as err import numpy as nu import cairo from process_funcs import bash from math import sqrt, log, exp, nan, inf, pi, floor, ceil, isfinite, isnan def main(set_name): def ok(p): return isfinite(p[0]) and p[0] >= 0 and isfinite(p[1]) and p[1] >= 0 # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Read point files: pts_file_a = f"keyframes/{set_name}-0.txt" pts_file_b = f"keyframes/{set_name}-1.txt" pts_file_c = f"keyframes/{set_name}-2.txt" pts_a = nu.loadtxt(pts_file_a) pts_b = nu.loadtxt(pts_file_b) pts_c = nu.loadtxt(pts_file_c) err.write(f"{nu.shape(pts_a) = }\n") pts = nu.zeros(nu.shape(pts_a)) pts_nan = nu.full((2,), nan) err.write(f"{nu.shape(pts_nan) = }\n") np = nu.size(pts_a, 0) err.write(f"{np = }\n") # Generate 30 frames for the a -> b transition nf = 30 frames = [] for kf in range(nf): t = kf / (nf-1) # Interpolating quadratic basis: Pa = 2*(t - 0.5)*(t - 1.0) Pb = 4*t*(1-t) Pc = 2*t*(t - 0.5) # Image size width, height = 300, 300 # Create surface, paint all white: surface = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height) ctx = cairo.Context(surface) ctx.set_source_rgb(1, 1, 1) ctx.paint() # Set stroke properties ctx.set_source_rgb(1, 0, 0) # red ctx.set_line_width(30.0) ctx.set_line_cap(cairo.LINE_CAP_ROUND) ctx.set_line_join(cairo.LINE_JOIN_ROUND) in_path = False for ip in range(np+1): # Interpolate point pa = pts_a[ip,:] if ip < np else pts_nan pb = pts_b[ip,:] if ip < np else pts_nan pc = pts_c[ip,:] if ip < np else pts_nan if ip < np and ok(pa) and ok(pb) and ok(pc): p = Pa*pa + Pb*pb + Pc*pc if not in_path: ctx.move_to(p[0], p[1]) else: ctx.line_to(p[0], p[1]) in_path = True else: ctx.stroke() in_path = False # Draw the polygonal: out_file = f"frames/{set_name}-{kf:03d}.png" surface.write_to_png(out_file) return # ---------------------------------------------------------------------- main(sys.argv[1])