> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.BjiClPprsV-/rev.76
 * 
 * authors: 
 *   Nick Bennett

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



boolean DEBUG = false;

int loopsPerFrame = 1;
color bgColor = color(0);

color fgColor1, fgColor2;

float centerX, centerY;

// number of pairs of divisions, as 
// sample section is mirrored once and
// total number is multiple of two
float radialDivisions = 18;
float divisionAngle = (2 * PI) / (2 * radialDivisions);

void setup() {
  size(400, 300);
//  size(screen.width, screen.height, P2D);
  
  colorMode(HSB, 255);
  fgColor1 = color(random(255), random(192, 255), 255);
//  fgColor2 = color(random(255), random(255), random(255));
  fgColor2 = color((hue(fgColor1) + 127)%255, saturation(fgColor1), brightness(fgColor1));
  
  centerX = (float)width / 2;
  centerY = (float)height / 2;
  
// Modeled region is pie slice from 0 to angle
// Render things there and simultaneously render 
// in the other regions 

  frameRate(30);
  background(bgColor);
  if(DEBUG) {
    stroke(255,0,0);
    line(centerX, centerY, 
          centerX + 200 * cos(0), 
          centerY + 200 * sin(0));
    stroke(0,255,0);
    line(centerX, centerY, 
          centerX + 200 * cos(divisionAngle), 
          centerY + 200 * sin(divisionAngle));     
  }  
  if(DEBUG) noLoop();
  if(DEBUG) stroke(255);
}

void draw() {
  for(int i = 0; i < loopsPerFrame; i++) {
//    stroke(0, random(255), 0, random(127));
//    color c = color(random(127,255), random(127), random(127), random(127));
//    color c = color(random(255), random(255), 54, random(127));
    color c = color(map(random(255), 0, 255, hue(fgColor1), hue(fgColor2)),
                    map(random(255), 0, 255, saturation(fgColor1), saturation(fgColor2)),
                    map(random(255), 0, 255, brightness(fgColor1), brightness(fgColor2)),
                    random(127));
    stroke(c);
    fill(c);
//    EllipseKaleid(random(width), random(height), random(10,40), centerX, centerY);
    strokeWeight(random(3, 10));
    LineKaleid(random(width), random(height), random(width), random(height), centerX, centerY);
//    strokeWeight(random(30));
//    PointKaleid(random(width), random(height), centerX, centerY);
  }
}

void mouseMoved() 
{
//  strokeWeight(30);
  color c = color(random(255), random(255), 255, random(255));
  stroke(c);
  strokeWeight(1);
  fill(c);
  EllipseKaleid(mouseX, mouseY, random(10, 60), centerX, centerY);
}


float AngleOnUnitCircle(float x, float y, float cx, float cy) {
  float tx = x - cx; 
  float ty = y - cy;
  float angle = atan2(ty, tx);

  // Compensating for atan2() returning a value
  // between -PI and PI
  if(angle < 0) {
    angle = 2 * PI + angle;
  }

  return angle;
}

void BoxKaleid(float x, float y, float w, float h) {
  
}


/* 

Attempting to do this in a simpler manner using the built-in
translate() and rotate() functions

void LineKaleid2(float x1, float y1, float x2, float y2, float cx, float cy) {
  pushMatrix();
  translate(cx, cy);
  for(int i=0;i<radialDivisions;i++) {
    if(DEBUG) println("i = " + i);
    rotate((float)i * (2 * divisionAngle));
    line(x1-cx, y1-cy, x2-cx, y2-cy);
//    println("
//    line(y1-cy, x1-cx, y2-cy, x2-cx);
  }
  popMatrix();
}
*/

void LineKaleid(float x1, float y1, float x2, float y2, float cx, float cy) {
  float angle1, angle2;
  float r1, r2;
  float nx1, ny1, nx2, ny2;
  
  // Finding radius and angle of first and second points in line
  // x = r * cos(theta)
  // y = r * sin(theta)
  // With the angles of these points, we can add the divisionAngle,
  // take the sine or cosine, and multiply by the radius to get
  // the new x and y positions
  r1 = sqrt(pow(x1 - cx, 2) + pow(y1 - cy, 2));
  angle1 = AngleOnUnitCircle(x1, y1, cx, cy);
  r2 = sqrt(pow(x2 - cx, 2) + pow(y2 - cy, 2));
  angle2 = AngleOnUnitCircle(x2, y2, cx, cy);
  if(DEBUG) println("Info on copied regions:");
  if(DEBUG) println("r1 = " + r1);
  if(DEBUG) println("angle1 = " + angle1);
  if(DEBUG) println("r2 = " + r2);
  if(DEBUG) println("angle2 = " + angle2);
  
  // Render the line in each of the copied regions
  for(int i = 0; i < radialDivisions; i++) {
    float tempAngle1 = angle1 + (float)i * (2 * divisionAngle);
    float tempAngle2 = angle2 + (float)i * (2 * divisionAngle);  
    nx1 = cx + r1 * cos(tempAngle1);
    ny1 = cy + r1 * sin(tempAngle1);
    nx2 = cx + r2 * cos(tempAngle2);
    ny2 = cy + r2 * sin(tempAngle2);
    line(nx1, ny1, nx2, ny2);
  }
  
  if(DEBUG) println("Info on mirrored regions:");
  // For the mirrored region, the angles get mirrored obviously
  angle1 = 2 * divisionAngle - angle1;
  angle2 = 2 * divisionAngle - angle2;
  if(DEBUG) println("r1 = " + r1);
  if(DEBUG) println("angle1 = " + angle1);
  if(DEBUG) println("r2 = " + r2);
  if(DEBUG) println("angle2 = " + angle2);

  // Render the line in each of the mirrored regions  
  for(int i = 0; i < radialDivisions; i++) {
    float tempAngle1 = angle1 + (float)i * (2 * divisionAngle);
    float tempAngle2 = angle2 + (float)i * (2 * divisionAngle);    
    nx1 = cx + r1 * cos(tempAngle1);
    ny1 = cy + r1 * sin(tempAngle1);
    nx2 = cx + r2 * cos(tempAngle2);
    ny2 = cy + r2 * sin(tempAngle2);
    line(nx1, ny1, nx2, ny2);
  }
}

void PointKaleid(float x1, float y1, float cx, float cy) {
  float angle1;
  float r1;
  float nx1, ny1;
  
  // Finding radius and angle of first and second points in line
  // x = r * cos(theta)
  // y = r * sin(theta)
  // With the angles of these points, we can add the divisionAngle,
  // take the sine or cosine, and multiply by the radius to get
  // the new x and y positions
  r1 = sqrt(pow(x1 - cx, 2) + pow(y1 - cy, 2));
  angle1 = AngleOnUnitCircle(x1, y1, cx, cy);
  
  // Render the point in each of the copied regions
  for(int i = 0; i < radialDivisions; i++) {
    float tempAngle1 = angle1 + (float)i * (2 * divisionAngle);
    nx1 = cx + r1 * cos(tempAngle1);
    ny1 = cy + r1 * sin(tempAngle1);
    point(nx1, ny1);
  }
  
  // For the mirrored region, the angle gets mirrored obviously
  angle1 = 2 * divisionAngle - angle1;

  // Render the point in each of the mirrored regions  
  for(int i = 0; i < radialDivisions; i++) {
    float tempAngle1 = angle1 + (float)i * (2 * divisionAngle);
    nx1 = cx + r1 * cos(tempAngle1);
    ny1 = cy + r1 * sin(tempAngle1);
    point(nx1, ny1);
  }
}

// For now only handles circles, where w=h
// If w!=h, this will not properly handle the rotation of
// the ellipse
void EllipseKaleid(float x1, float y1, float w, float cx, float cy) {
  float angle1;
  float r1;
  float nx1, ny1;
  
  // Finding radius and angle of first and second points in line
  // x = r * cos(theta)
  // y = r * sin(theta)
  // With the angles of these points, we can add the divisionAngle,
  // take the sine or cosine, and multiply by the radius to get
  // the new x and y positions
  r1 = sqrt(pow(x1 - cx, 2) + pow(y1 - cy, 2));
  angle1 = AngleOnUnitCircle(x1, y1, cx, cy);
  
  // Render the point in each of the copied regions
  for(int i = 0; i < radialDivisions; i++) {
    float tempAngle1 = angle1 + (float)i * (2 * divisionAngle);
    nx1 = cx + r1 * cos(tempAngle1);
    ny1 = cy + r1 * sin(tempAngle1);
    ellipse(nx1, ny1, w, w);
  }
  
  // For the mirrored region, the angle gets mirrored obviously
  angle1 = 2 * divisionAngle - angle1;

  // Render the point in each of the mirrored regions  
  for(int i = 0; i < radialDivisions; i++) {
    float tempAngle1 = angle1 + (float)i * (2 * divisionAngle);
    nx1 = cx + r1 * cos(tempAngle1);
    ny1 = cy + r1 * sin(tempAngle1);
    ellipse(nx1, ny1, w, w);
  }
}