harsh – AnimatedLoop

I started off with inspiration from D'arcy Thompson's "Theory of Transformations" - where he uses grid transformations to morph between different species of animals. I found his idea of being able to use simple mathematical equations to create transformations quite fascinating. So, I began to implement some of these systems, which included shear, scale, polar co-ordinate and exponential-scaling transformations. First, I tested this theory out on something simple - like a circle, before moving on to more complex geometries. I decided to keep my objects constructed as point clouds - as this kept my process of iteration quick, and the system scalable. By a sheer stroke of luck, I tried a polar coordinate transform before transforming it into a cartesian system - this created a really cool, point dissipation effect. I then began playing with these transformations, eventually closing in on using Mattise's Dancers - I thought the notion of an emergent composition from a seemingly random point cloud was quite interesting. It also connotated notions of the Gestalt and the border between familiarity and familiarity of a representation. I also thought that it made an interesting take on composition, referencing Mattise's methods in a digital medium. This was probably one the most iterations I have gone through in a week-long project, tweaking transformations, easing functions and point clouds numerous times before arriving at this result. I used the exponentialInOut and quinticInOut easing functions - both primarily to increase the time spent at the actual image and to speed up the transformation process. The process of crafting these transformations, both with morphing and easing functions was quite a novel one for me, having never really thought about computational craft before. Overall, I'm happy with the effect, and I think the easing and transformation functions work well. If I had more time on this, I would increase the complexity of the animation to emphasize this idea of composition - trying to recreate each object like pieces of paper cut by Mattise.

For this project, I did not really keep "sketches" - instead relying on Thompson's illustrations and descriptions as a means of generation:

 
 
 
//===================================================
// User-modifiable global variables.
var myNickname = "Harsh";
var nFramesInLoop = 120;
var bEnableExport = true;
 
 
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 
 
var circVals = [];
for(var i=0; i<pointsVals.length; i++){
  var curPointVals = pointsVals[i];
  circVals.push([curPointVals[0],curPointVals[1]*-1]);
}
 
 
var polarVals = []
for(var i=0; i<circVals.length; i++){
  var polarRadius = 30;
  var curPointVals = circVals[i];
  var cosX = polarRadius*Math.cos(curPointVals[0]);
  var sinY = polarRadius*Math.sin(curPointVals[1])
  polarVals.push([cosX,sinY]);
}
 
 
var shearVals = [];
for(var i=0; i<circVals.length; i++){
  var curPointVals = polarVals[i];
  var newX = curPointVals[0]-200;
  var newY = curPointVals[1]+200;
  shearVals.push([newX,newY]);
}
 
var shearDifferencesCartesian = []
for(var i=0; i<pointsVals.length; i++){
  var curCartValx = circVals[i][0];
  var curCartValy = circVals[i][1];
  var curShearValx = shearVals[i][0];
  var curShearValy = shearVals[i][1];
  var curTotalDifferenceX = curShearValx-curCartValx;
  var curTotalDifferenceY = curShearValy-curCartValy;
  shearDifferencesCartesian.push([curTotalDifferenceX,curTotalDifferenceY]);
}
 
var shearDifferencesPolar = []
for(var i=0; i<pointsVals.length; i++){
  var curPolarValx = polarVals[i][0];
  var curPolarValy = polarVals[i][1];
  var curShearValx = shearVals[i][0];
  var curShearValy = shearVals[i][1];
  var curTotalDifferenceX = curPolarValx-curShearValx;
  var curTotalDifferenceY = curPolarValy-curShearValy;
  shearDifferencesPolar.push([curTotalDifferenceX,curTotalDifferenceY]);
}
 
var cartesianDifferences = []
for(var i=0; i<pointsVals.length; i++){
  var curCartValx = circVals[i][0];
  var curCartValy = circVals[i][1];
  var curPolarValx = polarVals[i][0];
  var curPolarValy = polarVals[i][1];
  var curTotalDifferenceX = curPolarValx-curCartValx;
  var curTotalDifferenceY = curPolarValy-curCartValy;
  cartesianDifferences.push([curTotalDifferenceX,curTotalDifferenceY]);
}
 
var repVals = [];
for(var i=0; i<pointsVals.length; i++){
  var curPointVals = pointsVals[i];
  repVals.push([curPointVals[0],curPointVals[1]]);
}
 
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 
var circValsHead = [];
for(var i=0; i<headVals.length; i++){
  var curPointVals = headVals[i];
  circValsHead.push([curPointVals[0],curPointVals[1]*-1]);
}
 
 
var polarValsHead = []
for(var i=0; i<circValsHead.length; i++){
  var polarRadius = 30;
  var curPointVals = circValsHead[i];
  var cosX = polarRadius*Math.cos(curPointVals[0]);
  var sinY = polarRadius*Math.sin(curPointVals[1])
  polarValsHead.push([cosX,sinY]);
}
 
 
var shearValsHead = [];
for(var i=0; i<circValsHead.length; i++){
  var curPointVals = polarValsHead[i];
  var newX = curPointVals[0]+200;
  var newY = curPointVals[1]+200;
  shearValsHead.push([newX,newY]);
}
 
var shearDifferencesCartesianHead = []
for(var i=0; i<circValsHead.length; i++){
  var curCartValx = circValsHead[i][0];
  var curCartValy = circValsHead[i][1];
  var curShearValx = shearValsHead[i][0];
  var curShearValy = shearValsHead[i][1];
  var curTotalDifferenceX = curShearValx-curCartValx;
  var curTotalDifferenceY = curShearValy-curCartValy;
  shearDifferencesCartesianHead.push([curTotalDifferenceX,curTotalDifferenceY]);
}
 
var shearDifferencesPolarHead = []
for(var i=0; i<circValsHead.length; i++){
  var curPolarValx = polarValsHead[i][0];
  var curPolarValy = polarValsHead[i][1];
  var curShearValx = shearValsHead[i][0];
  var curShearValy = shearValsHead[i][1];
  var curTotalDifferenceX = curPolarValx-curShearValx;
  var curTotalDifferenceY = curPolarValy-curShearValy;
  shearDifferencesPolarHead.push([curTotalDifferenceX,curTotalDifferenceY]);
}
 
var cartesianDifferencesHead = []
for(var i=0; i<circValsHead.length; i++){
  var curCartValx = circValsHead[i][0];
  var curCartValy = circValsHead[i][1];
  var curPolarValx = polarValsHead[i][0];
  var curPolarValy = polarValsHead[i][1];
  var curTotalDifferenceX = curPolarValx-curCartValx;
  var curTotalDifferenceY = curPolarValy-curCartValy;
  cartesianDifferencesHead.push([curTotalDifferenceX,curTotalDifferenceY]);
}
 
var repValsHead = [];
for(var i=0; i<circValsHead.length; i++){
  var curPointVals = headVals[i];
  repValsHead.push([curPointVals[0],curPointVals[1]]);
}
 
 
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 
 
// Other global variables you don't need to touch.
var nElapsedFrames;
var bRecording;
var theCanvas;
//===================================================
function setup() {
  theCanvas = createCanvas(900, 900);
  bRecording = false;
  nElapsedFrames = 0;
}
//===================================================
function keyTyped() {
  if (bEnableExport) {
    if ((key === 'f') || (key === 'F')) {
      bRecording = true;
      nElapsedFrames = 0;
    }
  }
}
//===================================================
function draw() {
  // Compute a percentage (0...1) representing where we are in the loop.
  var percentCompleteFraction = 0;
  if (bRecording) {
    percentCompleteFraction = float(nElapsedFrames) / float(nFramesInLoop);
  } else {
    percentCompleteFraction = float(frameCount % nFramesInLoop) / float(nFramesInLoop);
  }
  // Render the design, based on that percentage.
  // This function renderMyDesign() is the one for you to change.
  renderMyDesign (percentCompleteFraction);
  // If we're recording the output, save the frame to a file.
  // Note that the output images may be 2x large if you have a Retina mac.
  // You can compile these frames into an animated GIF using a tool like:
  if (bRecording && bEnableExport) {
    var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png";
    print("Saving output image: " + frameOutputFilename);
    saveCanvas(theCanvas, frameOutputFilename, 'png');
    nElapsedFrames++;
 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
}
//===================================================
function renderMyDesign (percent) {
 
  background(13, 60, 85);
  smooth();
  stroke(0, 0, 0);
  strokeWeight(2);
 
  //----------------------
  var e = new p5.Ease(); // easing function object
 
  // percentSig = e.quadraticInOut(percent);
  // console.log(percentSig);
 
  percentSig = percent;
  if(0<=percentSig && percentSig<0.1){
 
    for(var i=0; i<circVals.length; i++){
      var curVal = polarVals[i];
      var curX = curVal[0];
      var curY = curVal[1];
      var curDifferenceX = shearDifferencesPolar[i][0];
      var curDifferenceY = shearDifferencesPolar[i][1];
      var newPerc = map(percent,0,0.1,0,1);
      var e = new p5.Ease(); // easing function object
      newPerc = e.exponentialInOut(newPerc);
      var newX = -1*((curDifferenceX*newPerc)-curX)
      var newY = -1*((curDifferenceY*newPerc)-curY)
      repVals[i] = [newX,newY];
    }
 
 
    for(var i=0; i<circValsHead.length; i++){
      var curVal = polarValsHead[i];
      var curX = curVal[0];
      var curY = curVal[1];
      var curDifferenceX = shearDifferencesPolarHead[i][0];
      var curDifferenceY = shearDifferencesPolarHead[i][1];
      var newPerc = map(percent,0,0.1,0,1);
      var e = new p5.Ease(); // easing function object
      newPerc = e.exponentialInOut(newPerc);
      var newX = -1*((curDifferenceX*newPerc)-curX)
      var newY = -1*((curDifferenceY*newPerc)-curY)
      repValsHead[i] = [newX,newY];
    }
 
  }
 
  else if(.1<=percentSig&& percentSig<0.66){
 
    for(var i=0; i<circVals.length; i++){
      var curVal = shearVals[i];
      var curX = curVal[0];
      var curY = curVal[1];
      var curDifferenceX = shearDifferencesCartesian[i][0];
      var curDifferenceY = shearDifferencesCartesian[i][1];
      var newPerc = map(percent,0.1,0.66,0,1)
      var e = new p5.Ease(); // easing function object
      newPerc = e.quinticInOut(newPerc);
      var newX = -1*((curDifferenceX*newPerc) - curX)
      var newY =  -1*((curDifferenceY*newPerc) - curY)
      repVals[i] = [newX,newY];
    }
 
 
    for(var i=0; i<circValsHead.length; i++){
      var curVal = shearValsHead[i];
      var curX = curVal[0];
      var curY = curVal[1];
      var curDifferenceX = shearDifferencesCartesianHead[i][0];
      var curDifferenceY = shearDifferencesCartesianHead[i][1];
      var newPerc = map(percent,0.1,0.66,0,1)
      var e = new p5.Ease(); // easing function object
      newPerc = e.quinticInOut(newPerc);
      var newX = -1*((curDifferenceX*newPerc) - curX)
      var newY =  -1*((curDifferenceY*newPerc) - curY)
      repValsHead[i] = [newX,newY];
    }
  }
 
  else if(.66<=percentSig&& percentSig<1){
 
    for(var i=0; i<circVals.length; i++){
      var curVal = circVals[i];
      var curX = curVal[0];
      var curY = curVal[1];
      var curDifferenceX = cartesianDifferences[i][0];
      var curDifferenceY = cartesianDifferences[i][1];
      var newPerc = map(percent,0.66,1,0,1)
      var e = new p5.Ease(); // easing function object
      newPerc = e.quadraticInOut(newPerc);
      var newX = (curDifferenceX*newPerc) + curX
      var newY =  (curDifferenceY*newPerc) + curY
      repVals[i] = [newX,newY];
    }
 
    for(var i=0; i<circValsHead.length; i++){
      var curVal = circValsHead[i];
      var curX = curVal[0];
      var curY = curVal[1];
      var curDifferenceX = cartesianDifferencesHead[i][0];
      var curDifferenceY = cartesianDifferencesHead[i][1];
      var newPerc = map(percent,0.66,1,0,1)
      var e = new p5.Ease(); // easing function object
      newPerc = e.quadraticInOut(newPerc);
      var newX = (curDifferenceX*newPerc) + curX
      var newY =  (curDifferenceY*newPerc) + curY
      repValsHead[i] = [newX,newY];
    }
  }
 
 
  for(var i=0; i<repVals.length; i++){
    //console.log((oldVals[i][0]+50),(oldVals[i][1]+50))
    push();
    fill(19, 149, 186);
    stroke(19, 149, 186);
    ellipse((repVals[i][0]+450),(repVals[i][1]+450),2,2);
    pop();
  }
 
 
  for(var i=0; i<repValsHead.length; i++){
    //console.log((oldVals[i][0]+50),(oldVals[i][1]+50))
    push();
    fill(241, 108, 32);
    stroke(241, 108, 32);
    ellipse((repValsHead[i][0]+450),(repValsHead[i][1]+450),5,5);
    pop();
  }
 
  //----------------------
  // Include some visual feedback.
  // fill(255, 0, 0);
  // noStroke();
  // textAlign(CENTER);
  // var percentDisplayString = "" + nf(percent, 1, 3);
  // text(percentDisplayString, 100, 200 - 15);
}