- Add primitive_libs/ with modular primitive loading (core, math, image, color, color_ops, filters, geometry, drawing, blending, arrays, ascii) - Effects now explicitly declare dependencies via (require-primitives "...") - Convert ascii-fx-zone from hardcoded special form to loadable primitive - Add _is_symbol/_is_keyword helpers for duck typing to support both sexp_effects.parser.Symbol and artdag.sexp.parser.Symbol classes - Auto-inject _interp and _env for primitives that need them - Remove silent error swallowing in cell_effect evaluation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
165 lines
2.6 KiB
Python
165 lines
2.6 KiB
Python
"""
|
|
Math Primitives Library
|
|
|
|
Trigonometry, rounding, clamping, random numbers, etc.
|
|
"""
|
|
import math
|
|
import random as rand_module
|
|
|
|
|
|
def prim_sin(x):
|
|
return math.sin(x)
|
|
|
|
|
|
def prim_cos(x):
|
|
return math.cos(x)
|
|
|
|
|
|
def prim_tan(x):
|
|
return math.tan(x)
|
|
|
|
|
|
def prim_asin(x):
|
|
return math.asin(x)
|
|
|
|
|
|
def prim_acos(x):
|
|
return math.acos(x)
|
|
|
|
|
|
def prim_atan(x):
|
|
return math.atan(x)
|
|
|
|
|
|
def prim_atan2(y, x):
|
|
return math.atan2(y, x)
|
|
|
|
|
|
def prim_sqrt(x):
|
|
return math.sqrt(x)
|
|
|
|
|
|
def prim_pow(x, y):
|
|
return math.pow(x, y)
|
|
|
|
|
|
def prim_exp(x):
|
|
return math.exp(x)
|
|
|
|
|
|
def prim_log(x, base=None):
|
|
if base is None:
|
|
return math.log(x)
|
|
return math.log(x, base)
|
|
|
|
|
|
def prim_abs(x):
|
|
return abs(x)
|
|
|
|
|
|
def prim_floor(x):
|
|
return math.floor(x)
|
|
|
|
|
|
def prim_ceil(x):
|
|
return math.ceil(x)
|
|
|
|
|
|
def prim_round(x):
|
|
return round(x)
|
|
|
|
|
|
def prim_min(*args):
|
|
if len(args) == 1 and hasattr(args[0], '__iter__'):
|
|
return min(args[0])
|
|
return min(args)
|
|
|
|
|
|
def prim_max(*args):
|
|
if len(args) == 1 and hasattr(args[0], '__iter__'):
|
|
return max(args[0])
|
|
return max(args)
|
|
|
|
|
|
def prim_clamp(x, lo, hi):
|
|
return max(lo, min(hi, x))
|
|
|
|
|
|
def prim_lerp(a, b, t):
|
|
"""Linear interpolation: a + (b - a) * t"""
|
|
return a + (b - a) * t
|
|
|
|
|
|
def prim_smoothstep(edge0, edge1, x):
|
|
"""Smooth interpolation between 0 and 1."""
|
|
t = prim_clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0)
|
|
return t * t * (3 - 2 * t)
|
|
|
|
|
|
def prim_random(lo=0.0, hi=1.0):
|
|
return rand_module.uniform(lo, hi)
|
|
|
|
|
|
def prim_randint(lo, hi):
|
|
return rand_module.randint(lo, hi)
|
|
|
|
|
|
def prim_gaussian(mean=0.0, std=1.0):
|
|
return rand_module.gauss(mean, std)
|
|
|
|
|
|
def prim_sign(x):
|
|
if x > 0:
|
|
return 1
|
|
elif x < 0:
|
|
return -1
|
|
return 0
|
|
|
|
|
|
def prim_fract(x):
|
|
"""Fractional part of x."""
|
|
return x - math.floor(x)
|
|
|
|
|
|
PRIMITIVES = {
|
|
# Trigonometry
|
|
'sin': prim_sin,
|
|
'cos': prim_cos,
|
|
'tan': prim_tan,
|
|
'asin': prim_asin,
|
|
'acos': prim_acos,
|
|
'atan': prim_atan,
|
|
'atan2': prim_atan2,
|
|
|
|
# Powers and roots
|
|
'sqrt': prim_sqrt,
|
|
'pow': prim_pow,
|
|
'exp': prim_exp,
|
|
'log': prim_log,
|
|
|
|
# Rounding
|
|
'abs': prim_abs,
|
|
'floor': prim_floor,
|
|
'ceil': prim_ceil,
|
|
'round': prim_round,
|
|
'sign': prim_sign,
|
|
'fract': prim_fract,
|
|
|
|
# Min/max/clamp
|
|
'min': prim_min,
|
|
'max': prim_max,
|
|
'clamp': prim_clamp,
|
|
'lerp': prim_lerp,
|
|
'smoothstep': prim_smoothstep,
|
|
|
|
# Random
|
|
'random': prim_random,
|
|
'randint': prim_randint,
|
|
'gaussian': prim_gaussian,
|
|
|
|
# Constants
|
|
'pi': math.pi,
|
|
'tau': math.tau,
|
|
'e': math.e,
|
|
}
|