Easing equations with 'Influence' and 'In-/Outgoing Velocity' like in Adobe After Effects

not sure what you mean

  • this reads easing from an ArrayList of draggable points (the y of the points is mapped to easing)
  • points are made with a sin() formula

I would be far more happy with it if when we could get ALL the points from curveVertex(pv.x, pv.y).

  • But I don’t know how.
  • See what I mean when you press and hold any key and watch the CAR going not on the black line (which would be cool) but from point to point



// see https://discourse.processing.org/t/dont-understand-what-this-code-means-easing/38588/3
// see https://discourse.processing.org/t/bezier-curve-move-weight-points/8872/3

// graph: 
// holding the curveVertex points in 2D - the core data. Here you add and edit your points. 
ArrayList<PointGraph> listPointsGraph = new ArrayList();

int step=1; 

boolean goodtogo=true;

boolean firstTimeKeyPressed=true;

//----

// move a sphere along the curve (Rollercoaster) optional 
boolean showRollercoasterFlag = false; 
int showRollercoaster_i; // current number of sphere on track for the Rollercoaster CAR 
int i2=0; // counter for the taken steps between 2 single points of track for rollercoaster  

//----

// for drag 
boolean hold=false; 
int hold_i = 0; 

//----

float easing = 0.05;

float targetX, targetY; 
float followingX, followingY; 

// ---------------------------------------------------------------------
// CORE functions 

void setup() {
  size(1850, 880);
  background(255);

  makeArrayList();  // the graph
}// func 

void draw() {
  drawForNormal();
}//draw

//------------------------------------------------------------------------------
// called by draw() 

void drawForNormal() {
  background(255);

  fill(0); // black 
  text("A black curve (curveVertex() command) composed of red points of an ArrayList, mouse drag to move points. Red points control the easing. \nA small car is giong on the graph like on a Rollercoaster, \n"
    +"but unfortunately it doesn't follow the black line (how to get data from curveVertex() command?) but goes directly between the red points."
    +"\nTry the sketch also with holding a key down and mouse drag (this is without the target/follower and in makeArrayList() a step of 90 for the for loop)", 
    17, 17, 
    width-100, 900); 

  // show ArrayList
  showArrayList(); 

  // drag? 
  if (hold) {    
    listPointsGraph.get(hold_i).pv.x=mouseX; 
    listPointsGraph.get(hold_i).pv.y=mouseY;
  }

  if (true) {
    rollerCoaster();
  }//if

  if (keyPressed)
    return; 
  if (goodtogo) {
    showTargetAndFollower();
  }
}// func 

void showTargetAndFollower() {
  // needs to have ALL points without any gaps (in makeArrayList())

  PointGraph pm = listPointsGraph.get(frameCount*10%width);
  float value = pm.getY();

  // we calculate the easing based on the graph: 
  //    * the lower the graph (nearer to height) the slower (0.0001)
  //    * the higher the graph (nearer to 150) the faster (0.9)
  easing = map(value, height, 150, 0.001, 0.59 ); 

  // manage x 
  targetX = frameCount*10%width;  // get the mouseX as target x coord
  float dx = targetX - followingX;  // calc delta between the current x and target x
  followingX += dx * easing; // move the current x a bit closer to the target x by adding delta BUT NOT the full delta but a value that is a smaller fraction 

  // Do the same with Y
  targetY = 100; // get the mouseY as target y coord
  // float dy = targetY - y;  // delta between the current y and target y
  // y += dy * easing; // move the current y a bit closer to the target y
  followingY = targetY;  

  stroke(255, 0, 0); 
  line(targetX-17, targetY, 
    targetX+17, targetY);

  noFill(); 
  stroke(0); 
  rect(followingX, followingY, 
    12, 12);
}

// -------------------------------------------------------------------------
// INPUTS 

void keyPressed() {
  if (firstTimeKeyPressed) {
    firstTimeKeyPressed=false; 
    step=90; 
    listPointsGraph.clear(); 
    makeArrayList();  // the graph
    step=1;
    goodtogo=false;
  }
}

void keyReleased() {
  if (!keyPressed) {
    step=1; 
    listPointsGraph.clear(); 
    makeArrayList();  // the graph
    goodtogo=true;
    firstTimeKeyPressed=true;
    showRollercoaster_i=0;
  }
}

void mouseReleased() {
  // end drag 
  hold = false;
}

// -------------------------------------------------------------------------

void makeArrayList() {
  // make Graph, called from setup()
  // 
  //float radiusX=300; 
  float radiusY=110;

  // float centerX=width/2;
  float centerY=height-130; 

  // start and end of graph and density 
  for (int angleStar = 0; angleStar <= width+100; angleStar += step) {

    float starX =angleStar; // centerX + (cos (radians(angleStar)) * radiusX);
    float starY = centerY + (sin (radians(angleStar)) * radiusY);

    // the part gets elevated 
    if (starX>220 &&
      starX<777) {
      // starY+=map(starX-220, 0, 310, -10, -42);
      starY=200;
    }

    PVector newPVector = new PVector(starX, starY);
    listPointsGraph.add (  new PointGraph ( newPVector, false) );   // 2D
  }//for

  // futher 
  //  listPointMy.get(65).pv.y -= 155;
}//func 

void showArrayList() {
  // show graph

  // show the curve with beginShape and endShape
  noFill();
  stroke(0);
  beginShape();
  int i=0;
  if (listPointsGraph.size()>0) {
    listPointsGraph.get(i).useAsCurveVertexPVector();
    for ( i = 0; i < listPointsGraph.size(); i++) {
      listPointsGraph.get(i).useAsCurveVertexPVector();
    }
    i=listPointsGraph.size()-1;
    listPointsGraph.get(i).useAsCurveVertexPVector();
  }//if
  endShape();

  //show the points (additionally) green OR Red 
  noStroke();
  float rad=3;
  boolean firstTimeShowingGreen=true; 
  for ( i = 0; i < listPointsGraph.size(); i++) {
    PointGraph pm = listPointsGraph.get(i);
    PVector pv=pm.pv;
    pm.selected=false;
    // if we are close to the mouse, color green, else red
    if (dist(mouseX, mouseY, pv.x, pv.y)<11 && firstTimeShowingGreen) {
      // near mouse 
      fill( 0, 255, 0); // green
      rad=3;
      firstTimeShowingGreen=false; 
      if (mousePressed&&!hold) {
        pm.selected=true;
        hold=true; 
        hold_i= i;
      }
    } else {
      // normal 
      pm.selected=false;
      fill(255, 0, 0);  // red
      rad=3;
    }
    pm.showAsRect(rad);
  }//for
  //
}//func

// ------------------------------------------------------------------------

void rollerCoaster() {
  // interprete the graph as a rollercoaster track with a CAR on it

  ellipseMode(CENTER);

  if (showRollercoaster_i > listPointsGraph.size()) {
    showRollercoaster_i=0;
  }

  // get two points between which the CAR currently is running  
  PointGraph pm1=listPointsGraph.get( showRollercoaster_i );
  PointGraph pm2=listPointsGraph.get( showRollercoaster_i+1 ); 

  // get dist between 2 points 
  float dist1 = pm1.pv.dist(pm2.pv);
  // calculate the steps between the 2 points depending on dist1 between them (smooth running) 
  float steps; // = 9;
  steps = (dist1 / 2.0);

  // calc t (can be seen as amt in lerp() / curvePoint) 
  float t = i2 / (float) steps;

  // similar to lerp() wth amt:  
  float x = curvePoint(pm1.pv.x, pm1.pv.x, pm2.pv.x, pm2.pv.x, t);
  float y = curvePoint(pm1.pv.y, pm1.pv.y, pm2.pv.y, pm2.pv.y, t);

  // different camera view for rollercoaster view
  // setRollerCoasterCamera(x, y, z, t); 

  // show ball&box [the rollercoaster car] 
  if (true) { 
    fill(255, 2, 244);
    noStroke(); 
    pushMatrix(); 
    translate(x, y);
    rect(0, 0, 9, 9);
    translate(4, -3);
    ellipse(0, 0, 7, 7); 
    popMatrix();
  }

  i2++; 
  if (i2>steps) {
    showRollercoaster_i++; 
    if (showRollercoaster_i>listPointsGraph.size()-2) { // little rough management at the end of arraylist... ??? 
      showRollercoaster_i=0;
    }//if
    i2=0;
  }//if
}//func

// ==================================================================

class PointGraph {

  // one point one the track 

  PVector pv;  // position 
  boolean selected=false; // selected y/n for mouse drag 

  // constructor 
  PointGraph( PVector pv_, boolean selected_ ) {
    pv        = pv_.copy();
    selected = selected_;
  } // constructor

  // -------------------------------------------------

  void showAsRect( float rad ) {
    pushMatrix();
    translate(pv.x, pv.y);
    rect(0, 0, rad, rad); 
    popMatrix();
  } // method

  float getY() {
    // used for easing
    return
      pv.y;
  } 

  void useAsCurveVertexPVector() {
    // use curveVertex with PVector as input  
    curveVertex(pv.x, pv.y);
  } // method 
  //
}//class
//