miyehn-Scope

miyehn-scope ←PDF

There’re two drops raining (quite obviously, I hope). Using this opportunity I also experimented a bit with Bezier curves and how to animate shapes by modifying the vertices. The process of changing shape worked pretty well. What I’m a bit unhappy with is that, since I can only make 10 frames, but the drops are moving across such a big distance, so their movement don’t look as continuous. I should’ve considered that into my design… Now I learned.

Below is the code (from Golan’s template).

// Template for KidzLabs/4M/Toysmith Animation Praxinoscope
// https://www.amazon.com/4M-3474-Animation-Praxinoscope/dp/B000P02HYC
// https://www.walmart.com/ip/Animation-Praxinoscope-Science-Kits-by-Toysmith-3474/45681503
// Developed for Processing 3.3.6 * http://processing.org
// 23 January 2018 * Golan Levin 
 
// See information about Processing PDF export at: 
// https://processing.org/reference/libraries/pdf/index.html
// PDF generated by Processing can be opened in Adobe Illustrator.
import processing.pdf.*;
boolean bRecordingPDF = false;
 
float inch = 72; 
float diamArtInner = inch * 1.50; 
float diamArtOuter = inch * 4.80; 
float diamCutInner = inch * 1.41; 
float diamCutOuter = inch * 4.875; 
float holeDy = inch * 0.23;
float holeDx = inch * 0.20;
float holeD = inch * 0.1;
 
final int nFrames = 10; 
int myFrameCount = 0;
int exportFrameCount = 0; 
boolean bAnimate = true; 
boolean bExportFrameImages = false;
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "praxinoscope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount < nFrames) {
      String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png";
      saveFrame("frames/" + filename);
      println("Saved: " + filename); 
      exportFrameCount++;
      if (exportFrameCount >= nFrames) {
        bExportFrameImages = false;
        exportFrameCount = 0;
      }
    }
  }
 
  if (bRecordingPDF) {
    endRecord();
    bRecordingPDF = false;
  }
}
 
 
//-------------------------------------------------------
void keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p': 
  case 'P':
    // Press 'p' to export a PDF for the Praxinoscope.
    bRecordingPDF = true; 
    break;
 
  case 'f': 
  case 'F': 
    // Press 'f' to export .png Frames (to make an animated .GIF)
    myFrameCount = 0; 
    exportFrameCount = 0; 
    bExportFrameImages = true;
    bAnimate = true; 
    break;
  }
}
 
//-------------------------------------------------------
void drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
void drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PDF. 
  if (!bRecordingPDF) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    int redWedge = 7; // assuming nFrames = 10
    for (int i=redWedge; i<=(redWedge+1); i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(255, 0, 0); 
      strokeWeight(2.0);
      line (pxi, pyi, pxo, pyo);
    }
    noFill(); 
    stroke(255, 0, 0); 
    strokeWeight(2.0);
    float startAngle = redWedge*TWO_PI/nFrames;
    float endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      pushMatrix();
      rotate(angle); 
      float originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      line (-inch/2, 0, inch/2, 0); 
      line (0, -inch/2, 0, inch/2); 
 
      popMatrix();
    }
  }
}
 
//-------------------------------------------------------
void drawAllFrames() {
  for (int i=0; i<nFrames; i++) {
    float angle = map(i, 0, nFrames, 0, TWO_PI); 
    float originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    pushMatrix();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    //drawArtFrame (whichFrame); 
    drawArtFrameAlternate (whichFrame); 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
void drawArtFrame (int whichFrame) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
  // Draw the frame number
  fill(0); 
  noStroke(); 
  textAlign(CENTER, CENTER); 
  text (whichFrame, -1, -47);
 
  // Draw a pulsating ellipse
  noFill(); 
  stroke(0);
  strokeWeight(1); 
  float t = map(whichFrame, 0, nFrames, 0, 1); 
  float diam = map(cos(t*TWO_PI), -1, 1, 25, 50); 
  ellipse(0, -45, diam, diam*0.8); 
 
  // Draw some expanding boxes, centered on the local origin
  int nBoxes = 3;
  for (int i=0; i<nBoxes; i++) {
    float F = ((whichFrame + i*nFrames)/(float)nBoxes)%nFrames;
    float rs = map(F, 0, nFrames-1, 0, 35); 
    float rx = 0; 
    float ry = 0; 
    float rg = map(F, 0, nFrames, 0, 255); 
    stroke(rg); 
    strokeWeight(1.0);
    rect(rx-rs/2, ry-rs/2, rs, rs);
  }
 
  // Draw some rotating spokes
  int nSpokes = 7;
  for (int i=0; i<nSpokes; i++) {
    float cx = 0; 
    float cy = 45; 
    float u = 0 - map(whichFrame + i*nFrames, 0, nFrames*nSpokes, 0, 1);
    float sx = cx + 15 * cos(u * TWO_PI); 
    float sy = cy + 15 * sin(u * TWO_PI); 
    stroke(0); 
    strokeWeight(1);
    line (cx, cy, sx, sy);
  }
}
 
//-------------------------------------------------------
void drawArtFrameAlternate(int whichFrame) { 
 
 pushMatrix();
 translate(0,-80);
 scale(0.6,0.6);
 fill(60,60,60);
 noStroke();
 
 
 float b1x=map(whichFrame,0,9,-20,-20); 
 float b1y=map(whichFrame,0,9,0,40);
 float b2x=map(whichFrame,0,9,-20,0); 
 float b2y=map(whichFrame,0,9,30,40);
 
 float b3x=map(whichFrame,0,9,20,20); 
 float b3y=map(whichFrame,0,9,30,40);
 float b4x=map(whichFrame,0,9,20,0); 
 float b4y=map(whichFrame,0,9,0,0);
 float x1=-20;
 float tmp = pow(whichFrame/10.0,3)*10.0;
 float y1=map(tmp,0,9,-30,300);
 float x2=16;
 float tmp2 = pow(shift(whichFrame)/10.0,3)*10.0;
 float y2 = map(tmp2,0,9,-30,300);
 
 beginShape();
 vertex(x1,y1);
 bezierVertex(x1+b1x,y1+b1y,x1+b2x,y1+b2y,x1,y1+map(whichFrame,0,9,30,40));
 bezierVertex(x1+b3x,y1+b3y,x1+b4x,y1+b4y,x1,y1);
 endShape();
 
 beginShape();
 vertex(x2,y2);
 bezierVertex(x2+b1x,y2+b1y,x2+b2x,y2+b2y,x2,y2+map(whichFrame,0,9,30,40));
 bezierVertex(x2+b3x,y2+b3y,x2+b4x,y2+b4y,x2,y2);
 endShape();
 
 popMatrix();
}
 
int shift(int whichFrame){
  if(whichFrame>=7){
    return whichFrame-7;
  }
  else return whichFrame+3;
}