"""Write the built-in design library into software/patterns//.thr. Run from the software folder: python3 tools/make_library.py Your own designs go in patterns/uploads/ (the web page's Upload button puts them there); this script never touches that folder. """ import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.dirname(HERE)) from sandtable import config, patterns, thr # noqa: E402 from sandtable.motion import Planner # noqa: E402 LIBRARY = { 'spirals': { 'spiral': ('spiral', {'loops': 20}), 'spiral-wide': ('spiral', {'loops': 12}), 'ripples': ('ripples', {}), 'ripples-fine': ('ripples', {'waves': 15, 'amplitude': 0.025, 'loops': 20}), 'galaxy-4': ('spiral_arms', {'arms': 4, 'turns': 1.0}), 'galaxy-8': ('spiral_arms', {'arms': 8, 'turns': 0.6}), }, 'flowers': { 'rose-5': ('rose', {'petals': 5, 'copies': 3, 'twist_deg': 12}), 'rose-8': ('rose', {'petals': 4}), 'rose-5-3': ('rose', {'petals': 5, 'denominator': 3, 'copies': 2, 'twist_deg': 36}), 'rose-7-4': ('rose', {'petals': 7, 'denominator': 4}), 'rose-twisted': ('rose', {'petals': 7, 'copies': 4, 'twist_deg': 12}), 'bouquet': ('rose', {'petals': 3, 'copies': 6, 'twist_deg': 20}), }, 'spirograph': { 'spirograph': ('spirograph', {}), 'spirograph-7': ('spirograph', {'big': 90, 'small': 35, 'pen': 0.7}), 'spirograph-5': ('spirograph', {'big': 120, 'small': 50, 'pen': 0.6}), 'spirograph-lace': ('spirograph', {'big': 100, 'small': 43, 'pen': 0.9}), }, 'geometric': { 'hexagons': ('polygons', {}), 'squares': ('polygons', {'sides': 4, 'layers': 50, 'twist_deg': 4}), 'triangles': ('polygons', {'sides': 3, 'layers': 45, 'twist_deg': 5}), 'octagons': ('polygons', {'sides': 8, 'layers': 40, 'twist_deg': 2}), 'string-art': ('string_art', {'points': 101, 'step': 40}), 'string-art-star': ('string_art', {'points': 61, 'step': 25}), 'sunburst': ('sunburst', {'rays': 24}), 'sunburst-fine': ('sunburst', {'rays': 40}), 'lissajous-3-2': ('lissajous', {'a': 3, 'b': 2, 'copies': 6, 'twist_deg': 30}), 'lissajous-5-4': ('lissajous', {'a': 5, 'b': 4, 'copies': 3, 'twist_deg': 20}), }, 'tools': { 'test_f': ('test_f', {}), }, } def main(dry_run=False): root = os.path.join(os.path.dirname(HERE), 'patterns') cfg = config.load() total = 0 for cat, items in LIBRARY.items(): for name, (gen, params) in items.items(): pts = patterns.generate(gen, **params) _, _, est = Planner(cfg, 0.0, cfg['machine']['rho_min_mm']).program(pts, erase=False) total += est print(f' {cat}/{name}: {len(pts)} points, about {est / 60:.0f} min') if not dry_run: os.makedirs(os.path.join(root, cat), exist_ok=True) args = ' '.join(f'{k}={v}' for k, v in params.items()) thr.save(os.path.join(root, cat, name + '.thr'), pts, header=f'sandtable generator {gen} {args}'.strip()) print(f' {sum(len(v) for v in LIBRARY.values())} designs, about {total / 3600:.1f} h in all (plus erasing)') if __name__ == '__main__': main(dry_run='--dry-run' in sys.argv)