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; } |