3 class Gimbal extends SCPattern {
5 private final boolean DEBUG_MANUAL_ABG = false;
6 private final int MAXIMUM_BEATS_PER_REVOLUTION = 100;
8 private boolean first_run = true;
9 private final Projection projection;
10 private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 20./MAXIMUM_BEATS_PER_REVOLUTION);
11 private final BasicParameter hueDeltaParam = new BasicParameter("HUED", 60./360);
12 private final BasicParameter fadeFromCoreParam = new BasicParameter("FADE", 1);
13 private final BasicParameter girthParam = new BasicParameter("GRTH", .18);
14 private final BasicParameter ringExtendParam = new BasicParameter("XTND", 1);
15 private final BasicParameter relativeSpeedParam = new BasicParameter("RLSP", .83);
16 private final BasicParameter sizeParam = new BasicParameter("SIZE", .9);
18 private final BasicParameter aP = new BasicParameter("a", 0);
19 private final BasicParameter bP = new BasicParameter("b", 0);
20 private final BasicParameter gP = new BasicParameter("g", 0);
22 Gimbal(GLucose glucose) {
24 projection = new Projection(model);
25 addParameter(beatsPerRevolutionParam);
26 addParameter(hueDeltaParam);
27 addParameter(fadeFromCoreParam);
28 addParameter(girthParam);
29 addParameter(ringExtendParam);
30 addParameter(relativeSpeedParam);
31 addParameter(sizeParam);
33 if (DEBUG_MANUAL_ABG) {
40 float a = 0, b = 0, g = 0;
42 public void run(double deltaMs) {
44 if (DEBUG_MANUAL_ABG) {
45 a = aP.getValuef() * (2 * PI);
46 b = bP.getValuef() * (2 * PI);
47 g = gP.getValuef() * (2 * PI);
49 float relativeSpeed = relativeSpeedParam.getValuef();
50 float time = millis() / 1000.f;
52 int beatsPerRevolution = (int) (beatsPerRevolutionParam.getValuef() * MAXIMUM_BEATS_PER_REVOLUTION) + 1;
53 float radiansPerMs = 2 * PI // radians / revolution
54 / beatsPerRevolution // beats / revolution
55 * lx.tempo.bpmf() // BPM beats / min
59 a += deltaMs * radiansPerMs * pow(relativeSpeed, 0);
60 b += deltaMs * radiansPerMs * pow(relativeSpeed, 1);
61 g += deltaMs * radiansPerMs * pow(relativeSpeed, 2);
67 float hue = lx.getBaseHuef();
68 float hue_delta = hueDeltaParam.getValuef() * 360;
70 float radius1 = model.xMax / 2 * sizeParam.getValuef();
71 float radius2 = ((model.xMax + model.yMax) / 2) / 2 * sizeParam.getValuef();
72 float radius3 = model.yMax / 2 * sizeParam.getValuef();
73 float girth = model.xMax * girthParam.getValuef();
74 Ring ring1 = new Ring((hue + hue_delta * 0) % 360, radius1, girth);
75 Ring ring2 = new Ring((hue + hue_delta * 1) % 360, radius2, girth);
76 Ring ring3 = new Ring((hue + hue_delta * 2) % 360, radius3, girth);
78 projection.reset(model)
79 // Translate so the center of the car is the origin
80 .translateCenter(model, 0, 0, 0);
82 for (Coord c : projection) {
83 //if (first_run) println(c.x + "," + c.y + "," + c.z);
86 rotate3d(c, PI/4, PI/4, PI/4);
87 color color1 = ring1.colorFor(c);
90 color color2 = ring2.colorFor(c);
93 color color3 = ring3.colorFor(c);
95 colors[c.index] = specialBlend(color1, color2, color3);
106 public Ring(float hue, float radius, float girth) {
108 this.radius = radius;
112 public color colorFor(Coord c) {
113 float theta = atan2(c.y, c.x);
114 float nearest_circle_x = cos(theta) * radius;
115 float nearest_circle_y = sin(theta) * radius;
116 float nearest_circle_z = 0;
118 float distance_to_circle
119 = sqrt(pow(nearest_circle_x - c.x, 2)
120 + pow(nearest_circle_y - c.y, 2)
121 + pow(nearest_circle_z - c.z * ringExtendParam.getValuef(), 2));
123 float xy_distance = sqrt(c.x*c.x + c.y*c.y);
124 return lx.hsb(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
136 class Zebra extends SCPattern {
138 private final Projection projection;
139 SinLFO angleM = new SinLFO(0, PI * 2, 30000);
142 SinLFO x, y, z, dx, dy, dz;
147 Zebra(GLucose glucose) {
149 projection = new Projection(model);
151 addModulator(angleM).trigger();
154 color colorFor(Coord c) {
155 float hue = lx.getBaseHuef();
161 c.x = c.x + millis() / 100.f;
166 int stripe_count = 12;
167 float stripe_width = model.xMax / (float)stripe_count;
168 if (Math.floor((c.x) / stripe_width) % 2 == 0) {
169 return lx.hsb(hue, 100, 100);
171 return lx.hsb((hue + 90) % 360, 100, 100);
177 if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
178 return lx.hsb(lx.getBaseHuef(), 100, 100);
180 return lx.hsb(0, 0, 0);
185 int isPositiveBit(float f) {
186 return f > 0 ? 1 : 0;
189 public void run(double deltaMs) {
190 float a = (millis() / 1000.f) % (2 * PI);
191 float b = (millis() / 1200.f) % (2 * PI);
192 float g = (millis() / 1600.f) % (2 * PI);
194 projection.reset(model)
195 // Translate so the center of the car is the origin
196 .translateCenter(model, 0, 0, 0);
198 for (Coord c : projection) {
199 // rotate3d(c, a, b, g);
200 colors[c.index] = colorFor(c);
208 boolean first_run = true;
209 private void log(String s) {
218 void rotate3d(Coord c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
226 float a1 = cosa*cosb;
227 float a2 = cosa*sinb*sing - sina*cosg;
228 float a3 = cosa*sinb*cosg + sina*sing;
229 float b1 = sina*cosb;
230 float b2 = sina*sinb*sing + cosa*cosg;
231 float b3 = sina*sinb*cosg - cosa*sing;
233 float c2 = cosb*sing;
234 float c3 = cosb*cosg;
236 float[] cArray = { c.x, c.y, c.z };
237 c.x = dotProduct(new float[] {a1, a2, a3}, cArray);
238 c.y = dotProduct(new float[] {b1, b2, b3}, cArray);
239 c.z = dotProduct(new float[] {c1, c2, c3}, cArray);
242 float dotProduct(float[] a, float[] b) {
244 for (int i = 0 ; i < a.length; ++i) {
250 color specialBlend(color c1, color c2, color c3) {
255 // force h1 < h2 < h3
263 float s1 = saturation(c1);
264 float s2 = saturation(c2);
265 float s3 = saturation(c3);
267 float b1 = brightness(c1);
268 float b2 = brightness(c2);
269 float b3 = brightness(c3);
270 float relative_b1 = b1 / (b1 + b2 + b3);
271 float relative_b2 = b2 / (b1 + b2 + b3);
272 float relative_b3 = b3 / (b1 + b2 + b3);
275 (h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360,
276 s1 * relative_b1 + s2 * relative_b2 + s3 * relative_b3,