Why is this interpolation not working?


    Aug 29 2011 | 5:21 pm
    Hi all,
    I am writing a javascript piece of code and for some reason it is not working. The idea is: I have 9 different jit.gl.gridshapes each with a different texture.
    When the function "randomize" is called, these pieces jump to a different location in space, but not suddenly, interpolating (tweeing) from the original position to the final position. These intermediate positions are calculated inside the js object and then sent to 9 different [receive] objects inside my patch.
    The problem: for some reason, the intermediate positions (tween) calculated by function interpolate(c) stops at a certain moment, so for example if the object's x coordinate should travel from 2.0 to 3.0 in a time defined by the counter (which goes from 0. to 1.), then it stops calculating at 2.6 and keeps on outputting 2.6, 2.6, 2.6, 2.6....until the counter stops.
    Hope I am making myself more or less clear and someone has the time to help me!
    //js code//////////////////////////////////////////////////
    inlets=1;
    outlets=0;
    var nPieces =9;
    var pieces = new Array(nPieces);
    var originPos = new Array(nPieces); //store actual positions, then generate new positions
    var finalPos = new Array(nPieces); //store actual positions, then generate new positions
    var sendObj = ["send0", "send1", "send2", "send3", "send4", "send5", "send6", "send7", "send8"];
    var rScale = 5;
    var counter = 0.0;
    var refreshCounter = 0.01;
    var interpYesNo = false;
    var ready = false;
    var PI = 3.141594;
    function piece(x, y, z, w, h) { //pieces constructor
    this.pos = [x,y, z];
    this.scale = [w,h, 1.0];
    this.vel = [0.0, 0.0, 0.0];
    }
    function setUpPieces () {
    for(i=0; i {
    pieces[i] = new piece(0.0, 0.0, 0.0, 1.0, 1.0);
    }
    }
    function randomPos () {
    return(((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale));
    }
    function calculateNewPositions() {
    //store origin and final pos
    for(i=0; i originPos[i] = pieces[i].pos;
    finalPos[i] = [randomPos(), randomPos(), randomPos()];
    }
    ready = true; //ready to start interpolation
    }
    //LINEAR INTERPOLATION
    function interpolation (initialPos, finalPos, time) {
    return(initialPos+time*(finalPos-initialPos));
    }
    function interpolate(c) {
    for(i=0; i {
    pieces[i].pos[0] = interpolation(originPos[i][0], finalPos[i][0], c);
    pieces[i].pos[1] = interpolation(originPos[i][1], finalPos[i][1], c);
    pieces[i].pos[2] = interpolation(originPos[i][2], finalPos[i][2], c);
    messnamed(sendObj[i], "position", pieces[i].pos[0], pieces[i].pos[1], pieces[i].pos[2]);
    }
    }
    function randomize() {
    if (interpYesNo == false) {
    interpYesNo = true;
    calculateNewPositions();
    }
    else return;
    }
    function updateCounter() {
    if (interpYesNo == true && ready == true) //if interpolation is ON, then
    {
    counter += refreshCounter;
    post(counter, "n");
    interpolate(counter);
    if (counter >=1.0)
    {
    interpYesNo = false;
    ready = false;
    counter = 0.0;
    }
    }
    }
    function bang(){
    updateCounter();
    }
    //end js code

    • Aug 29 2011 | 5:37 pm
      cool code. i would use a Task for that. did you try it?
    • Aug 29 2011 | 6:01 pm
      Never heard of Tasks before, I just found a tutorial... why do you think that a task could be useful in this case?
    • Aug 29 2011 | 7:06 pm
      I´m taking a look at the JS Tasks tutorial and thanks: yours was a great tip!!!
      By using tasks I don´t have to depend on the bang () function to trigger the counter. Instead, the updateCounter regulates its own timing and repetitions by itself.
      I still don´t know if this will solve the problem in the interpolation function. I will implement a task in this code and see if the problem is solved.
    • Aug 29 2011 | 8:35 pm
      So I re-wrote the code using tasks. The problem with the interpolation is still the same, the pieces seem to "freeze" at some point and do not complete the movement from the origin to final position
      //new js
      inlets=1;
      outlets=0;
      var nPieces =9;
      var pieces = new Array(nPieces);
      var originPos = new Array(nPieces); //store actual positions, then generate new positions
      var finalPos = new Array(nPieces); //store actual positions, then generate new positions
      var sendObj = ["send0", "send1", "send2", "send3", "send4", "send5", "send6", "send7", "send8"];
      var rScale = 5;
      var counter = 0.0;
      var refreshCounter = 0.01;
      var interpYesNo = false;
      var PI = 3.141594;
      //TASKS
      var tsk = new Task(updateCounter, this);
      tsk.interval = 50; //repeats each 50 ms
      function piece(x, y, z, w, h) { //pieces constructor
      this.pos = [x,y, z];
      this.scale = [w,h, 1.0];
      this.vel = [0.0, 0.0, 0.0];
      }
      function setUpPieces () {
      for(i=0; i {
      pieces[i] = new piece(0.0, 0.0, 0.0, 1.0, 1.0);
      messnamed(sendObj[i], "position", pieces[i].pos[0], pieces[i].pos[1], pieces[i].pos[2]);
      }
      }
      function randomPos () {
      return(((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale));
      }
      function calculateNewPositions() {
      //store origin and final pos
      for(i=0; i originPos[i] = pieces[i].pos;
      finalPos[i] = [randomPos(), randomPos(), randomPos()];
      }
      }
      //LINEAR INTERPOLATION
      function interpolation (initialPos, finalPos, time) {
      return(initialPos+time*(finalPos-initialPos));
      }
      function interpolate(c) {
      for(i=0; i {
      pieces[i].pos[0] = interpolation(originPos[i][0], finalPos[i][0], c);
      pieces[i].pos[1] = interpolation(originPos[i][1], finalPos[i][1], c);
      pieces[i].pos[2] = interpolation(originPos[i][2], finalPos[i][2], c);
      messnamed(sendObj[i], "position", pieces[i].pos[0], pieces[i].pos[1], pieces[i].pos[2]);
      }
      }
      function randomize() {
      if (interpYesNo == false) {
      interpYesNo= true;
      calculateNewPositions();
      tsk.repeat(); //start task
      }
      }
      function updateCounter() {
      if(counter < 1.0)
      {
      counter += refreshCounter;
      post(counter, "n");
      interpolate(counter);
      }
      else
      {
      counter = 0.0;
      interpYesNo = false;
      arguments.callee.task.cancel(); //cancel the task
      }
      }
      updateCounter.local = 1; //prevent triggering the task directly from outside the js
      function stop() {
      tsk.cancel();
      interpYesNo = false;
      }
      //end js
    • Aug 31 2011 | 4:39 pm
      I solved it, the problem was in the "interpolate(c)" function. I was calculating an interpolated position, and then storing it again as an initial position. So the interpolation trajectory became each time smaller and smaller...
      //INCORRECT FORM
      function interpolate(c) {
      for(i=0; i {
      pieces[i].pos[0] = interpolation(originPos[i][0], finalPos[i][0], c);
      pieces[i].pos[1] = interpolation(originPos[i][1], finalPos[i][1], c);
      pieces[i].pos[2] = interpolation(originPos[i][2], finalPos[i][2], c);
      messnamed(sendObj[i], "position", pieces[i].pos[0], pieces[i].pos[1], pieces[i].pos[2]);
      }
      }
      //CORRECT FORM. Just sends the interpolated values out
      //and does not store them anywhere
      function interpolate(c) {
      for(i=0; i {
      messnamed(sendObj[i], "position",
      interpolation(pieces[i].pos[0], finalPos[i][0], c),
      interpolation(pieces[i].pos[1], finalPos[i][1], c),
      interpolation(pieces[i].pos[2], finalPos[i][2], c));
      }
      }
      //////////////////////////////////////////////////////////////////////////
      //Complete corrected js code
      inlets=1;
      outlets=0;
      var nPieces =9;
      var pieces = new Array(nPieces);
      var finalPos = new Array(nPieces); //store actual positions, then generate new positions
      var sendObj = ["send0", "send1", "send2", "send3", "send4", "send5", "send6", "send7", "send8"];
      var rScale = 5;
      var counter = 0.0;
      var refreshCounter = 0.01;
      var interpYesNo = false;
      var PI = 3.141594;
      //TASKS
      var tsk = new Task(updateCounter, this);
      tsk.interval = 50; //repeats each 50 ms
      function piece(x, y, z, w, h) { //pieces constructor
      this.pos = [x,y, z];
      this.scale = [w,h, 1.0];
      this.vel = [0.0, 0.0, 0.0];
      }
      function setUpPieces () {
      for(i=0; i {
      pieces[i] = new piece(0.0, 0.0, 0.0, 1.0, 1.0);
      messnamed(sendObj[i], "position", pieces[i].pos[0], pieces[i].pos[1], pieces[i].pos[2]);
      }
      }
      function randomPos () {
      return(((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale));
      }
      function calculateNewPositions() {
      //store origin and final pos
      for(i=0; i //originPos[i] = pieces[i].pos;//DELETE THIS LINE
      finalPos[i] = [randomPos(), randomPos(), randomPos()];
      }
      }
      //LINEAR INTERPOLATION
      function interpolation (initialPos, finalPos, time) {
      return(initialPos+time*(finalPos-initialPos));
      }
      for(i=0; i {
      messnamed(sendObj[i], "position",
      interpolation(pieces[i].pos[0], finalPos[i][0], c),
      interpolation(pieces[i].pos[1], finalPos[i][1], c),
      interpolation(pieces[i].pos[2], finalPos[i][2], c));
      }
      }
      function randomize() {
      if (interpYesNo == false) {
      interpYesNo= true;
      calculateNewPositions();
      tsk.repeat(); //start task
      }
      }
      function updateCounter() {
      if(counter < 1.0)
      {
      counter += refreshCounter;
      post(counter, "n");
      interpolate(counter);
      }
      else
      {
      counter = 0.0;
      interpYesNo = false;
      for(i = 0; i {
      pieces[i].pos = finalPos[i]; //STORE FINAL POSITION AS INITIAL POSITION }
      arguments.callee.task.cancel(); //cancel the task
      }
      }
      updateCounter.local = 1; //prevent triggering the task directly from outside the js
      function stop() {
      tsk.cancel();
      interpYesNo = false;
      }
      //end js code
    • Aug 31 2011 | 4:50 pm
      cool! nice one. maybe i will steal your code now. ha ha.
    • Sep 06 2011 | 11:16 pm
      Hi again
      Still working on interpolation. Now that simple interpolation works, I want my object to grow and shrink in a back and forth movement "like a boomerang". Each time I call my function, I want to "launch it" once.
      In this case, origin and final scaling are the same.
      I have tried using a cubic interpolation but it does not work properly. What formula should I use for this?
      Thanks in advance.....
      //code
      //COSINE INTERPOLATION
      function cosineInterpolation(initialPos, finalPos, time)
      {
      var mu2 = (1-Math.cos(time*PI))/2;
      return(initialPos*(1-mu2)+finalPos*mu2);
      }
      //CUBIC INTERPOLATION
      function cubicInterpolation(y0, y1, y2, y3,time)
      {
      var a0,a1,a2,a3,time2;
      time2 = time*time;
      a0 = y3 - y2 - y0 + y1;
      a1 = y0 - y1 - a0;
      a2 = y2 - y0;
      a3 = y1;
      return(a0*time*time2+a1*time2+a2*time+a3);
      }
      //MY FUNCTION
      function interpolateParabola(c) {
      messnamed(sendObj[id], "scale", cubicInterpolation(p.scale[0],
      p.scale[0]*Xscale, p.scale[0]*Xscale, p.scale[0], c),
      p.scale[1],
      p.scale[2]);
      }
      //end js code
      BTW check out this web by Paul Bourke, he describes the several interpolation methods and includes C++ functions
    • Sep 08 2011 | 6:28 pm
      Got it!
      I changed my approach. Instead of taking a counter from 0.0 to 1.0 as a time value for the interpolation formula, I take the number of iterations of the task.
      //js code
      var parab = new Task(interpolateParabola, this);
      parab.interval = 10;
      glob.maxIterations = 50;
      function startParabola() {
      if(parabYesNo == false) {
      parabYesNo = true;
      parab.repeat();
      }
      }
      function interpolateParabola() {
      mappedIter = map_range(iter, 0, glob.maxIterations, 0.0, 1.0);
      if(iter < glob.maxIterations/2)
      {
      messnamed(sendObj[id], "scale", cosineInterpolation(p.scale[0],
      p.scale[0]*Xscale, mappedIter),
      p.scale[1],
      p.scale[2]);
      }
      else
      {
      messnamed(sendObj[id], "scale", cosineInterpolation(p.scale[0]*Xscale, p.scale[0], mappedIter),
      p.scale[1],
      p.scale[2]);
      }
      iter++;
      if(iter == glob.maxIterations) {
      parabYesNo = false;
      iter = 0;
      arguments.callee.task.cancel(); //cancel the task
      }
      }
      //end js code
      function stopParabola() {
      if(parab.running == true) {
      parab.cancel();
      parabYesNo = false;
      }
      }
    • Sep 09 2011 | 10:19 am
      thanks a lot for posting back!