-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspiral_shape.py
More file actions
81 lines (63 loc) · 2.73 KB
/
spiral_shape.py
File metadata and controls
81 lines (63 loc) · 2.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/usr/bin/env python3
"""
Spiral Module
=============
Draws Archimedean spirals: r = a + b*θ
The spiral grows outward (or inward) as it rotates.
"""
import numpy as np
from fractions import Fraction
from math import pi, sin
from main import TransformModule
class SpiralShapeModule(TransformModule):
"""
Archimedean spiral generator.
Configuration:
start_radius: Starting radius
end_radius: Ending radius
turns: Number of spiral turns
direction: 1 for outward, -1 for inward
cycles: Number of times to draw the spiral (for moiré with transforms)
"""
def _load_config(self):
"""Load spiral configuration."""
self.start_radius = self._getfloat('start_radius', 0.0)
self.end_start_radius = self._getfloat('end_start_radius', self.start_radius)
self.end_radius = self._getfloat('end_radius', 50.0)
self.end_end_radius = self._getfloat('end_end_radius', self.end_radius)
self.turns = self._getfloat('turns', 3.0)
self.direction = self._getint('direction', 1)
self.cycles = self._getfloat('cycles', 1.0)
self.lobe = self._getfloat('lobe', 0.0)
self.lobe_n = self._getfloat('lobe_n', 1.0)
def transform(self, z: complex, t: float) -> complex:
"""
Generate point on spiral at time t.
With cycles > 1, draws the spiral multiple times.
Combined with transforms, creates moiré effects.
"""
# Normalize t to [0,1] for global interpolation
period = float(self._pipeline_period)
t_norm = t / period if period > 0 else t
# Convert to position within cycles
t_in_cycles = t_norm * self.cycles
# Position within current cycle [0, 1)
t_frac = t_in_cycles % 1.0
# Interpolate drift for start/end radii
sr = self._interpolate(self.start_radius, self.end_start_radius, t_norm, 'start_radius')
er = self._interpolate(self.end_radius, self.end_end_radius, t_norm, 'end_radius')
# Radius grows linearly within each spiral
r = sr + t_frac * (er - sr)
# Angle for this single spiral
angle = self.direction * t_frac * self.turns * 2 * pi
# Per-revolution lobe: radius varies within each revolution
if self.lobe != 0:
r += self.lobe * sin(angle * self.lobe_n)
point = r * np.exp(1j * angle)
return z + point
@property
def natural_period(self) -> Fraction:
"""Period based on cycles."""
return Fraction(self.cycles).limit_denominator(1000)
def __repr__(self):
return f"SpiralModule({self.start_radius}→{self.end_radius}, {self.turns} turns, cycles={self.cycles})"