class Gimbal extends SCPattern {
+ private final PerfTimer perf = new PerfTimer();
+
private final boolean DEBUG_MANUAL_ABG = false;
private final int MAXIMUM_BEATS_PER_REVOLUTION = 100;
private boolean first_run = true;
- private final Projection projection;
- private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 20./MAXIMUM_BEATS_PER_REVOLUTION);
+ private final LXProjection projection;
+ private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 25./MAXIMUM_BEATS_PER_REVOLUTION);
private final BasicParameter hueDeltaParam = new BasicParameter("HUED", 60./360);
private final BasicParameter fadeFromCoreParam = new BasicParameter("FADE", 1);
private final BasicParameter girthParam = new BasicParameter("GRTH", .18);
private final BasicParameter bP = new BasicParameter("b", 0);
private final BasicParameter gP = new BasicParameter("g", 0);
- Gimbal(GLucose glucose) {
- super(glucose);
- projection = new Projection(model);
+ Gimbal(LX lx) {
+ super(lx);
+ projection = new LXProjection(model);
addParameter(beatsPerRevolutionParam);
addParameter(hueDeltaParam);
addParameter(fadeFromCoreParam);
Ring ring2 = new Ring((hue + hue_delta * 1) % 360, radius2, girth);
Ring ring3 = new Ring((hue + hue_delta * 2) % 360, radius3, girth);
- projection.reset(model)
+ projection.reset()
// Translate so the center of the car is the origin
- .translateCenter(model, 0, 0, 0);
+ .center();
- for (Coord c : projection) {
+ for (LXVector c : projection) {
//if (first_run) println(c.x + "," + c.y + "," + c.z);
- rotate3d(c, a, 0, 0);
- rotate3d(c, PI/4, PI/4, PI/4);
+ rotate3dA(c, a);
+ rotate3dPiOver4(c);
color color1 = ring1.colorFor(c);
- rotate3d(c, 0, b, 0);
+ rotate3dB(c, b);
color color2 = ring2.colorFor(c);
- rotate3d(c, 0, 0, g);
+ rotate3dG(c, g);
color color3 = ring3.colorFor(c);
colors[c.index] = specialBlend(color1, color2, color3);
}
- first_run = false;
+ first_run = false;
}
class Ring {
float hue;
float radius, girth;
+ float _multiplier;
public Ring(float hue, float radius, float girth) {
this.hue = hue;
this.radius = radius;
this.girth = girth;
+ this._multiplier = 100. / girth * fadeFromCoreParam.getValuef();
}
- public color colorFor(Coord c) {
+ public color colorFor(LXVector c) {
+ float xy_distance_to_circle = sqrt(c.x * c.x + c.y * c.y) - radius;
+ float z_distance_to_circle = c.z * ringExtendParam.getValuef();
+
+ float distance_to_circle
+ = sqrt(xy_distance_to_circle * xy_distance_to_circle
+ + z_distance_to_circle * z_distance_to_circle);
+
+ return lx.hsb(this.hue, 100, 100. - distance_to_circle * _multiplier);
+
+ /* PRE-OPTIMIZED IMPLEMENTATION
float theta = atan2(c.y, c.x);
float nearest_circle_x = cos(theta) * radius;
float nearest_circle_y = sin(theta) * radius;
float xy_distance = sqrt(c.x*c.x + c.y*c.y);
return lx.hsb(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
+ */
}
-
+
}
}
+class PerfTimer {
+
+ private final Map<String, Integer> m = new TreeMap<String, Integer>();
+ private String current_phase = null;
+ private int current_phase_start_time = 0;
+ private int total_time = 0;
+
+ public void start(String phase_name) {
+ if (current_phase != null) {
+ stop();
+ }
+ current_phase = phase_name;
+ current_phase_start_time = millis();
+ }
+
+ public void stop() {
+ int current_time = millis();
+
+ assert(current_phase != null);
+ assert(current_phase_start_time != 0);
+ int time_ellapsed = current_time - current_phase_start_time;
+ m.put(current_phase,
+ (m.containsKey(current_phase) ? m.get(current_phase) : 0)
+ + time_ellapsed);
+
+ current_phase = null;
+ current_phase_start_time = 0;
+ total_time += time_ellapsed;
+ }
+
+ public void report() {
+ if (random(0, 60 * 4) < 1) {
+ println("~~~~~~~~~~~~~~~~~~");
+ for (String phase_name : m.keySet()) {
+ print(phase_name);
+ for (int i = phase_name.length(); i < 30; ++i) {
+ print(" ");
+ }
+ println("" + (float) m.get(phase_name) / total_time);
+ }
+ }
+ }
+
+}
+
+
class Zebra extends SCPattern {
- private final Projection projection;
+ private final LXProjection projection;
SinLFO angleM = new SinLFO(0, PI * 2, 30000);
/*
_P size;
*/
- Zebra(GLucose glucose) {
- super(glucose);
- projection = new Projection(model);
+ Zebra(LX lx) {
+ super(lx);
+ projection = new LXProjection(model);
addModulator(angleM).trigger();
}
- color colorFor(Coord c) {
+ color colorFor(LXVector c) {
float hue = lx.getBaseHuef();
float b = (millis() / 1200.f) % (2 * PI);
float g = (millis() / 1600.f) % (2 * PI);
- projection.reset(model)
+ projection.reset()
// Translate so the center of the car is the origin
- .translateCenter(model, 0, 0, 0);
+ .center();
- for (Coord c : projection) {
+ for (LXVector c : projection) {
// rotate3d(c, a, b, g);
colors[c.index] = colorFor(c);
}
}
-void rotate3d(Coord c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
+float HALF_OF_ONE_OVER_SQRT2_MINUS_1 = (1./sqrt(2) - 1) / 2;
+float HALF_OF_ONE_OVER_SQRT2_PLUS_1 = (1./sqrt(2) + 1) / 2;
+float SQRT2 = sqrt(2);
+
+/** Equivalent to rotate3d(c, a, 0, 0); */
+void rotate3dA(LXVector c, float a) {
+ float ox = c.x, oy = c.y;
+ float cosa = cos(a);
+ float sina = sin(a);
+ c.x = ox * cosa - oy * sina;
+ c.y = ox * sina + oy * cosa;
+}
+/** Equivalent to rotate3d(c, 0, b, 0); */
+void rotate3dB(LXVector c, float b) {
+ float ox = c.x, oz = c.z;
+ float cosb = cos(b);
+ float sinb = sin(b);
+ c.x = ox * cosb + oz * sinb;
+ c.z = oz * cosb - ox * sinb;
+}
+/** Equivalent to rotate3d(c, 0, 0, g); */
+void rotate3dG(LXVector c, float g) {
+ float oy = c.y, oz = c.z;
+ float cosg = cos(g);
+ float sing = sin(g);
+ c.y = oy * cosg - oz * sing;
+ c.z = oz * cosg + oy * sing;
+}
+/** Equivalent to rotate3d(c, PI/4, PI/4, PI/4); */
+void rotate3dPiOver4(LXVector c) {
+ float ox = c.x, oy = c.y, oz = c.z;
+ c.x = ox / 2 + oy * HALF_OF_ONE_OVER_SQRT2_MINUS_1 + oz * HALF_OF_ONE_OVER_SQRT2_PLUS_1;
+ c.y = ox / 2 + oy * HALF_OF_ONE_OVER_SQRT2_PLUS_1 + oz * HALF_OF_ONE_OVER_SQRT2_MINUS_1;
+ c.z = - ox / SQRT2 + oy / 2 + oz / 2;
+}
+
+void rotate3d(LXVector c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
+ float ox = c.x, oy = c.y, oz = c.z;
+
float cosa = cos(a);
float cosb = cos(b);
float cosg = cos(g);
float c1 = -sinb;
float c2 = cosb*sing;
float c3 = cosb*cosg;
-
- float[] cArray = { c.x, c.y, c.z };
- c.x = dotProduct(new float[] {a1, a2, a3}, cArray);
- c.y = dotProduct(new float[] {b1, b2, b3}, cArray);
- c.z = dotProduct(new float[] {c1, c2, c3}, cArray);
+
+ c.x = ox * a1 + oy * a2 + oz * a3;
+ c.y = ox * b1 + oy * b2 + oz * b3;
+ c.z = ox * c1 + oy * c2 + oz * c3;
}
float dotProduct(float[] a, float[] b) {
float b1 = brightness(c1);
float b2 = brightness(c2);
float b3 = brightness(c3);
- float relative_b1 = b1 / (b1 + b2 + b3);
- float relative_b2 = b2 / (b1 + b2 + b3);
- float relative_b3 = b3 / (b1 + b2 + b3);
+ float b_denominator = b1 + b2 + b3;
+ float relative_b1 = b1 / b_denominator;
+ float relative_b2 = b2 / b_denominator;
+ float relative_b3 = b3 / b_denominator;
return lx.hsb(
(h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360,