Source code for klotho.dynatos.envelopes.utils.curves

"""
Curve generation and mapping utilities for envelopes.

This module provides functions for generating various types of curves
including linear and exponential lines, arch/swell shapes, and value
mapping with curve transformations.
"""

import numpy as np

__all__ = [
    'line',
    'arch',
    'map_curve',
]

[docs] def line(start=0.0, end=1.0, steps=100, curve=0.0): """ Generate a curved line from start to end value over n steps. Parameters ---------- start : float, optional Starting value (default is 0.0). end : float, optional Ending value (default is 1.0). steps : int, optional Number of steps (default is 100). curve : float, optional Shape of the curve. Negative for exponential, positive for logarithmic, 0 for linear (default is 0.0). Returns ------- numpy.ndarray Array of values following the specified curve. """ if curve == 0: return np.linspace(start, end, steps) t = np.linspace(0, 1, steps) curved_t = np.exp(curve * t) - 1 curved_t = curved_t / (np.exp(curve) - 1) return start + (end - start) * curved_t
[docs] def arch(base=0.0, peak=1.0, steps=100, curve=0.0, axis=0): """ Generate a swelling curve that rises and falls. Starts and ends at the base value, peaking at the peak value. Parameters ---------- base : float, optional Starting and ending value (default is 0.0). peak : float, optional Peak value (default is 1.0). steps : int, optional Number of steps (default is 100). curve : float or list of float, optional Shape of the curve. A single number applies the same curve to both sides (negative for exponential, positive for logarithmic). A list of two values sets ascending and descending curves independently (default is 0.0). axis : float, optional Position of the peak (-1 to 1). 0 centers the peak, negative shifts earlier, positive shifts later (default is 0). Returns ------- numpy.ndarray Array of values following a swell curve. """ axis = np.clip(axis, -1, 1) split_point = int((0.5 + axis * 0.4) * steps) if isinstance(curve, (list, tuple)) and len(curve) == 2: up_curve, down_curve = curve else: up_curve = down_curve = curve up = line(base, peak, split_point + 1, up_curve) down = line(peak, base, steps - split_point, down_curve) return np.concatenate([up[:-1], down])
[docs] def map_curve(value, in_range, out_range, curve=0.0): """ Map a value from an input range to an output range with optional curve shaping. Parameters ---------- value : float Input value to map. in_range : tuple of float (min, max) for the input range. out_range : tuple of float (min, max) for the output range. curve : float, optional Shape of the curve. Negative for exponential, positive for logarithmic, 0 for linear (default is 0.0). Returns ------- float Mapped value with curve applied. """ normalized = np.interp(value, in_range, (0, 1)) if curve != 0: normalized = np.exp(curve * normalized) - 1 normalized = normalized / (np.exp(curve) - 1) return np.interp(normalized, (0, 1), out_range)