> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.TFwoWwBY$5r/rev.40
 * 
 * authors: 
 *   GoToLoop

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



/**
 * Rotating Arcs (v2.5.2)
 * by  Marius Watz
 * mod GoToLoop
 * 
 * Using sin/cos lookup tables, blends colors, and draws a series of
 * rotating arcs on the screen.
 *
 * GitHub.com/processing/processing-docs/blob/master/content/
 * examples/Demos/Graphics/RotatingArcs/RotatingArcs.pde
 *
 * forum.Processing.org/two/discussion/14071/
 * converting-java-code-to-python-for-dataviz#Item_11
 *
 * studio.ProcessingTogether.com/sp/pad/export/ro.9AqEIV-5Q9sCx
 */

static final int ARC_LINES = 0, ARC_BARS = 1, ARC_SOLIDS = 2;
static final int FPS = 60, SMOOTH = 2, NUM = 100, A = 210;
static final float WEIGHT = 1.0, SIXTH_PI = THIRD_PI * .5;
static final boolean ONLINE = 1/2 == 1/2.;

// Trig lookup tables borrowed from Toxi; cryptic but effective.
static final float PRECISION = 2.0, RADS = .5 * DEG_TO_RAD*PRECISION;
static final int LENGTH = (int) (360/PRECISION), LUTS = LENGTH<<1;

static final float[] COS_SIN = new float[LUTS];
//static // Comment this out for JS Mode!
{ // Fill the tables
  for (int i = 0; i < LUTS; i += 2) {
    COS_SIN[i]   = cos(RADS*i);
    COS_SIN[i+1] = sin(RADS*i);
  }
}

final float[] pt = new float[6*NUM]; // spd, rotX, rotY, deg, rad, width
final int[] styles = new int[2*NUM]; // color, render styles

int clockwise = 1;
boolean paused;

void setup() {
  size(800, 650, P3D);
  smooth(SMOOTH);
  frameRate(FPS);
  strokeWeight(WEIGHT);
  initArcShapes();
}

void draw() {
  background(0);

  translate(width>>1, height>>1);
  rotateX(SIXTH_PI);
  rotateY(SIXTH_PI);

  for (int idx = 0, i = 0; i < styles.length; idx += 6, i += 2) {
    pushMatrix();

    final float spd = clockwise * pt[idx]; // Rotation speed
    rotateX(pt[idx+1] += spd);
    rotateY(pt[idx+2] += spd * .5);

    final float deg = pt[idx+3], rad = pt[idx+4], w = pt[idx+5];
    final color c = styles[i];

    switch (styles[i+1]) {
    case ARC_LINES:
      stroke(c);
      noFill();
      arcLines(0, 0, deg, rad, w);
      break;

    case ARC_BARS:
      fill(c);
      noStroke();
      arcBars(0, 0, deg, rad, w);
      break;

    case ARC_SOLIDS:
      fill(c);
      noStroke();
      arcSolids(0, 0, deg, rad, w);
    }

    popMatrix();
  }

  if (!ONLINE)  frame.setTitle("FPS: " + round(frameRate));
}

void mousePressed() {
  switch (mouseButton) {
  case LEFT:
    clockwise *= -1;
    break;

  case RIGHT:
    if (paused ^= true)  noLoop();
    else                 loop();
    break;

  case CENTER:
    initArcShapes();
  }
}

// Draw arc lines:
void arcLines(float x, float y, float deg, float rad, float w) {
  final int angs = min((int) (2.0/PRECISION*deg), LUTS-1);
  final int lines = (int) w >> 1;

  for (int j = 0; j < lines; rad += 2.0, ++j) {
    beginShape();
    for (int i = 0; i < angs; i += 2)
      vertex(x + rad*COS_SIN[i], y + rad*COS_SIN[i+1]);
    endShape();
  }
}

// Draw arc line with bars:
void arcBars(float x, float y, float deg, float rad, float w) {
  final int angs = min((int) (.5/PRECISION*deg), LUTS-5);
  final float rdw = rad+w;

  beginShape(QUADS);
  for (int i = 0; i < angs; i += 8) {
    final float c1 = COS_SIN[i], s1 = COS_SIN[i+1];
    final float c2 = COS_SIN[i+4], s2 = COS_SIN[i+5];

    vertex(x + rad*c1, y + rad*s1);
    vertex(x + rdw*c1, y + rdw*s1);
    vertex(x + rdw*c2, y + rdw*s2);
    vertex(x + rad*c2, y + rad*s2);
  }
  endShape();
}

// Draw solid arc:
void arcSolids(float x, float y, float deg, float rad, float w) {
  final int angs = min((int) (2.0/PRECISION*deg), LUTS-1);
  final float rdw = rad+w;

  beginShape(QUAD_STRIP);
  for (int i = 0; i < angs; i += 2) {
    final float c = COS_SIN[i], s = COS_SIN[i+1];

    vertex(x + rad*c, y + rad*s);
    vertex(x + rdw*c, y + rdw*s);
  }
  endShape();
}

// Get blend of two colors:
color blendColors(float fract, 
  color r, color g, color b, 
  color rr, color gg, color bb, color a) {

  rr -= r;
  gg -= g;
  bb -= b;

  return color(r + rr*fract, g + gg*fract, b + bb*fract, a);
}

void initArcShapes() {
  for (int i = 0; i < pt.length; i += 6) { // Get spd, rotX, rotY, deg, rad, wdt:
    pt[i] = DEG_TO_RAD/50 * random(5, 30); // Speed of rotation

    pt[i+1] = random(TAU); // Random x axis rotation
    pt[i+2] = random(TAU); // Random Y axis rotation

    // Short to quarter-circle arcs:
    pt[i+3] = random(1) > .9? 10 * (int) random(8, 27) : random(60, 80);

    pt[i+4] = 5 * (int) random(2, 50); // Radius. (Space them out nicely)

    pt[i+5] = random(1) > .9? random(40, 60) : random(4, 32); // Width of band
  }

  for (int i = 0; i < styles.length; i += 2) { // Get colors
    final float rnd = random(1), f = random(1);

    if      (rnd < .3)  styles[i] = blendColors(f, 255, 0, 100, 255, 0, 0, A);
    else if (rnd < .5)  styles[i] = blendColors(f, 200, 255, 0, 50, 120, 0, A);
    else if (rnd < .7)  styles[i] = blendColors(f, 0, 153, 255, 170, 225, 255, A);
    else if (rnd < .9)  styles[i] = blendColors(f, 200, 255, 0, 150, 255, 0, A);
    else                styles[i] = 0xdcFFFFFF;

    styles[i+1] = (int) random(3); // Pick arc style
  }
}