> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.eWd$AyVnMAf/rev.767
 * 
 * authors: 
 *   
 *   Wolfe

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



/* @pjs preload="favicon.ico,/static/uploaded_resources/p.467/poppy.png"; */

// Mathematically rotating image pixel by pixel
// this is one of my "What happens if..."

// left  / A  >> rotate by center to left
// right / D  >> rotate by center to right
// if pressed mouse button rotate whole image around mouse cursor
// mouse drag >> move image (translate)

// up    / W  >> scale - zoom in
// down  / S  >> scale - zoom out
// in zooming in you can see 

// space >> swap image between "big" (cannon fodder) poppy (slow for js)
// and tiny sketchpad.cc logo (faster rotating)


PImage img;

ArrayList pixs;
float totalScale=1;

boolean imgSwap = true;

float totalX, totalY;
PVector lsUp = new PVector (0,1);
PVector lsRight = new PVector (1,0);


void setup() {
  size(600, 400);

  totalX=width/2;
  totalY=height/2;


  if (imgSwap) img = loadImage("favicon.ico");
  else img = loadImage("/static/uploaded_resources/p.467/poppy.png");
  //img = loadImage("pics/poppy.png");

  pixs = new ArrayList();

  for (int x = 0; x<img.width; x++) {
    for (int y = 0; y<img.width; y++) {

      pixs.add(new Pixel(x+width/2-img.width/2, y+height/2-img.height/2, img.get(x, y)));
    }
  }
  
  
  imgSwap = !imgSwap;
}

/////////////////////////////////

void draw() {

  //    image(img, width/2-img.width/2, height/2-img.height/2);
  if (imgSwap) background(0);
  else background(255);


  for (int i = pixs.size()-1; i >= 0; i--) { 
    Pixel pixel = (Pixel) pixs.get(i);
    //pixel.paint(width/2-img.width/2, height/2-img.height/2);
    pixel.paint();
  }
}

void rotateLocalSpace(float anchorX, float anchorY, float angle){
    PVector tempUp = lsUp.get();
    PVector tempRight = lsRight.get();
    
    angle = radians(angle);
    

    lsUp.x = tempUp.x * cos(angle) - tempUp.y * sin(angle);
    lsUp.y = tempUp.x * sin(angle) + tempUp.y * cos(angle);

    lsRight.x = tempRight.x * cos(angle) - tempRight.y * sin(angle);
    lsRight.y = tempRight.x * sin(angle) + tempRight.y * cos(angle);
    
    }

/////////////// CLASS //////////////
class Pixel {
  float x, y, angl, scal; 
  int clr;


  Pixel(float _x, float _y, int _clr) {
    x = _x;
    y = _y;
    clr = _clr;
  }

  void paint() {
    paint(0, 0);
  }
  ///////////
  void paint(int _x, int _y) {
    pushStyle();
    fill(clr);
    stroke(clr);

        rectMode(CENTER);
    if (clr != 0) rect(x+_x, y+_y, 1, 1);


    popStyle();
  }


  ///////////
  void rotate(float anchorX, float anchorY, float angle) {
    float rotX, rotY, origX, origY;
    PVector temp = new PVector(x - anchorX,y - anchorY);
 
    origX = rotX = x - anchorX;
    origY = rotY = y - anchorY;

    x -= rotX;
    y -= rotY;

    angle = radians(angle);

    rotX = origX * cos(angle) - origY * sin(angle);
    rotY = origX * sin(angle) + origY * cos(angle);


    x += rotX; // get it back to absolute position on screen
    y += rotY;
  }

  ///////////  
  void translate(float newX, float newY) {
    x += newX;
    y += newY;
  }

  void scale(float scaleX, float scaleY) {

    //    x = x - width/2;
    //    y = y - height/2;

    x = x - totalX;
    y = y - totalY;

    x *= scaleX;
    y *= scaleY;

    x = x + totalX;
    y = y + totalY;
    //    x = x + width/2;
    //    y = y + height/2;
  }
} 

////////////////////////////////////////////////////
void keyPressed() {
  float rotAmount = 10;
  float scaleAmount = 1.05;




  switch (keyCode) {

  case RIGHT:
  case 68:
    for (int i = pixs.size()-1; i >= 0; i--) { 
      Pixel pixel = (Pixel) pixs.get(i);
      if (mousePressed) pixel.rotate(mouseX, mouseY, rotAmount);
      else pixel.rotate(totalX, totalY, rotAmount);
    }
    if (mousePressed) rotate(mouseX, mouseY, rotAmount);




    break;

  case LEFT:
  case 65:

    for (int i = pixs.size()-1; i >= 0; i--) { 
      Pixel pixel = (Pixel) pixs.get(i);
      if (mousePressed) pixel.rotate(mouseX, mouseY, -rotAmount);
      else  pixel.rotate(totalX, totalY, -rotAmount);
    }
    if (mousePressed) rotate(mouseX, mouseY, -rotAmount);

    break;

  case UP:
  case 87:
    for (int i = pixs.size()-1; i >= 0; i--) { 
      Pixel pixel = (Pixel) pixs.get(i);
      pixel.scale(scaleAmount, scaleAmount);
    }
    totalScale += scaleAmount;
    break;


  case DOWN:
  case 83:
    for (int i = pixs.size()-1; i >= 0; i--) { 
      Pixel pixel = (Pixel) pixs.get(i);
      pixel.scale(1/scaleAmount, 1/scaleAmount);
    }
    totalScale -= scaleAmount;
    break;
    
    case 32: // restart = swap image
    setup();
    break 
  }
  //println(totalScale);
}


void mouseDragged() {
  for (int i = pixs.size()-1; i >= 0; i--) { 
    Pixel pixel = (Pixel) pixs.get(i);
    pixel.translate(mouseX-pmouseX, mouseY-pmouseY);
  }
  totalX += mouseX - pmouseX;
  totalY += mouseY - pmouseY;
  //println(totalX+","+totalY);
}



void rotate(float anchorX, float anchorY, float angle) {
  float rotX, rotY, origX, origY;

  origX = rotX = totalX - anchorX;
  origY = rotY = totalY - anchorY;

  totalX -= rotX;
  totalY -= rotY;

  angle = radians(angle);

  rotX = origX * cos(angle) - origY * sin(angle);
  rotY = origX * sin(angle) + origY * cos(angle);


  totalX += rotX; 
  totalY += rotY;
}