# Rotation and Easing

**URL:** https://discourse.processing.org/t/rotation-and-easing/5704
**Category:** Coding Questions
**Created:** [November 19, 2018, 8:11am UTC](https://discourse.processing.org/t/rotation-and-easing/5704 "2018-11-19T08:11:27Z")
**Posts on this page:** 19
**Page:** 1

<div class="post-metadata">

### Author: ![phoebus](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/phoebus/32/481_2.png) [@phoebus](https://discourse.processing.org/u/phoebus)
#### Post date: [November 19, 2018, 8:11am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/1 "2018-11-19T08:11:27Z")

</div>

Hello

In my sketch I want to controle the rotation of a wheel and add a bit of easing to the rotation to give some feeling of weight to the wheel.  
I have it doing what I want but, the easing is messed up by the gap between 0 and 360°

You will understand the problem very easily if you try the sketch

How would you solve this problem ?

here is the code

```auto
int cx, cy;
float radius = 400;
float rot = 0;

float hypo ;
float mySin ;   
float myCos ; 
float alpha;

float easing = 0.1;

void setup() {
  size(700, 700);

  cx = width / 2;
  cy = height / 2;
}

void draw() {

  background(128);
  update();
  render();
}

void update() {

  hypo = dist(mouseX, mouseY, cx, cy);
  mySin = (mouseY - cy) / hypo;   
  myCos = (mouseX - cx)/ hypo; 

  if (mySin > 0) {
    alpha = acos(myCos);
  } else {
    alpha = (2*PI) - acos(myCos);
  }

  float targetRot = alpha;
  float dRot = targetRot - rot;

  rot += dRot * easing;
}

void render() {
  pushMatrix();
  translate(width/2, height/2); 

  rotate (rot);
  fill(255);
  ellipse(0, 0, radius, radius);

  fill(128);
  ellipse(150, 0, 50, 50);

  popMatrix();
}

```

---

<div class="post-metadata">

### Author: ![hamoid](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hamoid/32/58_2.png) [@hamoid](https://discourse.processing.org/u/hamoid)
#### Post date: [November 19, 2018, 9:20am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/2 "2018-11-19T09:20:15Z")

</div>

I think this should help:

> <https://stackoverflow.com/questions/2708476/rotation-interpolation>

---

<div class="post-metadata">

### Author: ![brunoruchiga](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/brunoruchiga/32/2235_2.png) [@brunoruchiga](https://discourse.processing.org/u/brunoruchiga)
#### Post date: [November 19, 2018, 2:06pm UTC](https://discourse.processing.org/t/rotation-and-easing/5704/3 "2018-11-19T14:06:48Z")

</div>

I tried to calculate the shortest way and it seems to work:

```auto
  if(rot - alpha > alpha - (rot - TWO_PI)) {
    rot -= TWO_PI;
  } else if(alpha - rot > rot - (alpha - TWO_PI)) {
    rot += TWO_PI;
  }

  float targetRot = alpha;
  float dRot = targetRot - rot;

  rot += dRot * easing;

```

The logic of my code is: if rotating the angle all the way +TWO\_PI or -TWO\_PI makes distance to get shorter, than do it.

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [November 20, 2018, 3:12am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/4 "2018-11-20T03:12:39Z")

</div>

@phoebus , i could not stop play with that excellent idea,  
but i could not solve the problem, but thanks to  
@brunoruchiga can now show this version:

```auto
// https://discourse.processing.org/t/rotation-and-easing/5704
PVector myMouse = new PVector();
float rot = 0, alpha, dalpha, easing = 0.03;
// __________________________________________________________
void setup() {
  size(600, 600);
  stroke(120,120,120);
}
// __________________________________________________________
void draw() {
  myMouse.set( mouseX, mouseY, 0);
  myMouse.sub(width/2, height/2, 0);
  alpha = myMouse.heading();
  dalpha = (alpha-rot)/PI;
  if ( dalpha < -1) rot -= TWO_PI; // @brunoruchiga
  else if ( dalpha > 1 ) rot += TWO_PI;
  rot += (alpha -rot) * easing; // @phoebus
  // draw
  background(0, 0, 50);
  translate(width/2, height/2); 
  fill(170, 170, 0);
  ellipse(0, 0, 400, 400);
  rotate (rot);
  fill(170, 170, 170);
  ellipse(150, 0, 100, 100);
}

```

---

<div class="post-metadata">

### Author: ![phoebus](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/phoebus/32/481_2.png) [@phoebus](https://discourse.processing.org/u/phoebus)
#### Post date: [November 20, 2018, 5:44am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/5 "2018-11-20T05:44:02Z")

</div>

EXCALTY !

thank you so much @brunoruchiga, you nailed it !

😃

---

<div class="post-metadata">

### Author: ![henri](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/henri/32/2035_2.png) [@henri](https://discourse.processing.org/u/henri)
#### Post date: [October 30, 2019, 10:13am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/6 "2019-10-30T10:13:32Z")

</div>

Hi,

I have been using this excellent sketch to simulate the behaviour of some rotating objects in Cinema 4D having converted the sketch to Python.

I am wondering if there is a way to increase the easing from - let’s say - 0.1 to 0.5 and then back from 0.5 to 0.1

I am trying to more realistically simulate some sort of acceleration/deceleration curve. I think this would be a way of doing it.

Any other suggestions?

---

<div class="post-metadata">

### Author: ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)
#### Post date: [October 30, 2019, 10:38am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/7 "2019-10-30T10:38:47Z")

</div>

You could take the easing values from a array that you fill from sin function

Or use sin directly together with map

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [October 30, 2019, 10:54am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/8 "2019-10-30T10:54:22Z")

</div>

> [@henri](#):
>
> I am trying to more realistically simulate some sort of acceleration/deceleration curve.

you can try using the mouseY  
means if top go slow, if bottom, go strong.

```auto
rot += (alpha -rot) * constrain( easing *height/(height-mouseY),0.01,0.1); 

```

---

<div class="post-metadata">

### Author: ![henri](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/henri/32/2035_2.png) [@henri](https://discourse.processing.org/u/henri)
#### Post date: [October 30, 2019, 11:19am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/9 "2019-10-30T11:19:13Z")

</div>

Hi @kll,

Thanks for your reply. This doesn’t seem to be generating a changing value between 0.01 and 0.1

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [October 30, 2019, 12:41pm UTC](https://discourse.processing.org/t/rotation-and-easing/5704/10 "2019-10-30T12:41:33Z")

</div>

no, but is the effect that what you want?

play more

```auto
  float easing_var = easing *height/(height-mouseY);
  print(easing_var);
  easing_var = constrain(easing_var,0.01,0.3);
  println(" limit "+easing_var);
  rot += (alpha -rot) * easing_var; // @phoebus

```

but it feels to strong now

the constrain has 2 jobs,

- limit the effect ( but should not be needed with good math )
- limit against mouse leaves canvas

---

<div class="post-metadata">

### Author: ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)
#### Post date: [October 30, 2019, 10:09pm UTC](https://discourse.processing.org/t/rotation-and-easing/5704/11 "2019-10-30T22:09:59Z")

</div>

> [@henri](#):
>
> I am trying to more realistically simulate some sort of acceleration/deceleration curve.

I was tinkering with the original post to simulate angular acceleration\deceleration.  
Just sharing…

It behaves very differently with rotation direction.

🙂

```auto
int cx, cy;
float radius = 400;
float rot = 0;

float hypo ;
float mySin ;   
float myCos ; 
float alpha;

float easing = .01f;

float mod;
float lastRot;

// GLV Added
float loc = 0;
float vel = 0;
float acc = TAU/2000;
int i;

public void settings()
  {  
  size(1000, 700); 
  }

public void setup() 
  {
  cx = width / 2;
  cy = height / 2;
  background(0);
  }

public void draw() 
  {
  //background(0);
  if (mousePressed) 
    {
    update();
    }
  render();
  }

public void update() 
  {
  hypo = dist(mouseX, mouseY, cx, cy);
  mySin = (mouseY - cy) / hypo;   
  myCos = (mouseX - cx)/ hypo; 

  if (mySin > 0) {
    alpha = acos(myCos);
  } else {
    alpha = (2*PI) - acos(myCos);
  }

  float targetRot = alpha;
  float dRot = targetRot - rot;
  //rot += dRot * easing;  
  
  rot += (loc/20); // Change this value for "speed"
  lastRot = rot;

  float trot = dRot;  
  loc += vel; //angle
  vel += acc; //angular acceleration
  if (loc < 0) 
    {
    vel = 0;
    loc = 0;
    }  
  
  if (loc >= trot) 
    {
    //vel = -vel;
    //loc = trot;
    vel = 0;
    loc = trot;
    }
  
  //println(rot, lastRot, rot-lastRot);
  println(loc, vel, acc);
  }

public void render() 
  {
 pushMatrix();
  translate(2*width/3, height/2); 

  strokeWeight(5);
  stroke(0, 255, 0);
  rotate (rot);
  fill(128);
  ellipse(0, 0, radius, radius);

  fill(0, 255, 0);
  ellipse(150, 0, 50, 50);
 popMatrix();
  
  stroke(255, 255, 0);
  strokeWeight(5);
  point(50*loc+width/4, i++);
  if (i>height) 
    {
    i = 0;
    background(0);
    }  
  }

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f1bc18f1cdceabe6c8eb335576a59ba0b5945f9d.png)

🙂

---

<div class="post-metadata">

### Author: ![henri](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/henri/32/2035_2.png) [@henri](https://discourse.processing.org/u/henri)
#### Post date: [October 31, 2019, 9:17am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/12 "2019-10-31T09:17:40Z")

</div>

Hey @kll

Yes this is working. Okay, I get it - the ball has a kind of behaviour where it struggles to keep up against a kind of gravity pulling the ball back down. Nice, thanks for sharing this 🙂

My real goal is to achieve a sketch where:

- the ball registers the target

- the ball begins to accelerate towards the target (ideally with an acceleration curve/non linear)

- the ball is locked on to the target and can keep up with the target so long as the target doesn’t exceed the ball’s predetermined max speed

- once the ball looses the target the ball decelerates

I think I have a way to go!

---

<div class="post-metadata">

### Author: ![henri](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/henri/32/2035_2.png) [@henri](https://discourse.processing.org/u/henri)
#### Post date: [October 31, 2019, 9:18am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/13 "2019-10-31T09:18:24Z")

</div>

@glv, that’s really cool! Thanks for sharing

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [October 31, 2019, 9:23am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/14 "2019-10-31T09:23:54Z")

</div>

thanks,  
that sounds a little like my old

> auto shooter !! NOT A GAME !!

actually my first PVector exercise

- search
- move ( speed like easing )
- shoot
- next target …

```auto
// https://discourse.processing.org/t/bug-with-arraylist/5949
// 11/2018 kll / my first game ever, good its not really a game
// make a arraylist of pvector points
// calc shortest distance to the next target, aim, fire + remove the point from array

int idt, pmax = 10;
ArrayList<PVector> points = new ArrayList<PVector>(); // list of points
PVector target = new PVector(0, 0); // position of cross line
boolean theend = false, shoot = false;

int k = 0, kmax = 30; //firing circles
float tdist, newdist, speedf = 0.04; // speed factor multiplied with distance gives realistic targeting movement

void setup() {
  size( 300, 300);
  for (int i = 0; i < pmax; i++) points.add(new PVector(random(-width/2, width/2), random(-height/2, height/2)));
  //for ( PVector p : points ) println(p);
  println("targets: "+points.size());
}

void draw_lines() {
  stroke(200, 0, 0);
  line(target.x, -height/2, target.x, height/2); 
  line(-width/2, target.y, width/2, target.y);
}

void draw_points() {
  for (int i = 0; i < points.size(); i++) { 
    if ( i == idt ) stroke(200, 0, 0);  
    else noStroke();
    fill(0, 200, 0);
    ellipse(points.get(i).x, points.get(i).y, 8, 8);
  }
}

int get_nearest() {
  int idx = -1; // init to not found
  tdist = width; // init to max
  for (int i = 0; i < points.size(); i++) {
    newdist = dist(points.get(i).x, points.get(i).y, target.x, target.y);
    if ( newdist < tdist ) { 
      tdist = newdist; 
      idx = i;
    }
  }
  return idx; // give index of nearest target
}

void aim() {
  if ( idt > -1 ) {
    PVector waytotarget = points.get(idt).copy();
    waytotarget.sub(target);
    if ( waytotarget.mag() > 0.5 ) { // thats close enough
      waytotarget.setMag(waytotarget.mag()*speedf); // calc faster to short step in that direction
      target = target.add(waytotarget); // change target
    } else { 
      if ( !shoot ) println("shoot at "+idt); // only print 
      shoot = true;
      points.remove(idt);
    }
  } else { 
    println("i win, but now i am alone!"); 
    theend = true;
  }
}

void fire() { // only if shoot = true
  fill(200, 100, 0);
  stroke(255, 0, 0); 
  strokeWeight(3);
  ellipse(target.x, target.y, 2*k, 2*k); // growing red circle
  strokeWeight(1);
  k++;
  if ( k >= kmax ) {  
    shoot = false; 
    k = 0;
  }
}

void show_end() {
  fill(0, 200, 0);
  rect(-50, -25, 100, 40);
  fill(200, 0, 0);
  text(" I WIN ! ", -20, 0); // well, what a wonder if you play alone and targets not move
}

void draw() {
  background(200, 200, 0);
  translate(width/2, height/2);
  if ( !theend ) {
    draw_lines(); // cross lines
    draw_points(); // all points fix pos, same size / red stroke for next target
    idt = get_nearest(); // next ( nearest ) target
    if ( !shoot ) aim(); // not walk while firing
    else fire(); // some show / red circles
  } else show_end(); // all over, no play again button
}

```

---

<div class="post-metadata">

### Author: ![henri](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/henri/32/2035_2.png) [@henri](https://discourse.processing.org/u/henri)
#### Post date: [October 31, 2019, 9:31am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/15 "2019-10-31T09:31:52Z")

</div>

Haha, that’s great.

Interesting, I guess a very important point that is missing from the original sketch is first determining how far away the target is.

Although, that is kind of happening with dalpha no?

```auto
  if ( dalpha < -1) rot -= TWO_PI; // @brunoruchiga
  else if ( dalpha > 1 ) rot += TWO_PI;
  rot += (alpha -rot) * easing_var; // @phoebus

```

If dalpha was more specifically targeted, that could be a way of simulating a different kind of acceleration?

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [October 31, 2019, 9:36am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/16 "2019-10-31T09:36:48Z")

</div>

if you talk about physical acceleration yes, both would be wrong

why not try @Chrisir s idea  
of a sin speed acceleration-deceleration

---

<div class="post-metadata">

### Author: ![henri](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/henri/32/2035_2.png) [@henri](https://discourse.processing.org/u/henri)
#### Post date: [October 31, 2019, 9:45am UTC](https://discourse.processing.org/t/rotation-and-easing/5704/17 "2019-10-31T09:45:40Z")

</div>

Oops, totally missed his comment

---

<div class="post-metadata">

### Author: ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)
#### Post date: [October 31, 2019, 4:37pm UTC](https://discourse.processing.org/t/rotation-and-easing/5704/18 "2019-10-31T16:37:04Z")

</div>

here is sketch with lerp function

```auto

float mousePosX=100, mousePosY=100, 
  mousePosXFinal=100, mousePosYFinal=100;

boolean startUp=false; 

float amt; 
float maxAmt = 0.066; // WAS 0.025

int i=0; 
float initalDist1;

void setup() {
  size(500, 500);
  background(255);
  frameRate(20);
}

void draw() {
  background(255);

  // show grid 
  for (int i = 0; i < width; i += 50) {
    line(i, 0, i, height);
  }
  for (int i = 0; i < height; i += 50) {
    line(0, i, width, i);
  }

  // move red rect 
  float dist1 = dist(mousePosX, mousePosY, mousePosXFinal, mousePosYFinal);
  // Are we in the starting phase?
  if (startUp &&
    amt<maxAmt && 
    dist1>initalDist1/2) { // 
    // Yes, slowly accelerate 
    amt += 0.0011;
  } else { // OR else if (amt>=0.025)
    // No, we slowly decelerate 
    if (startUp)
      println("hit");
    startUp=false; 
    amt = map (dist1, 0, 900, 0.06, maxAmt);
  }
  ellipse(i++, height-(float)amt*1900, 5, 5); 
  mousePosX = lerp(mousePosX, mousePosXFinal, amt);
  mousePosY = lerp(mousePosY, mousePosYFinal, amt);
  if (dist1<0.029) {
    if (amt>0)
      println("Thank you");
    amt=0;
    mousePosX = mousePosXFinal;
    mousePosY = mousePosYFinal;
  }
  // show red rect
  fill(255, 0, 0);
  rect(mousePosX, mousePosY, 50, 50);
  text(amt, 31, 31);
}

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

void mousePressed() {
  // receive new target position

  // search mousePosXFinal  
  for (int i = 0; i < width; i += 50) {
    if (mouseX<=i+50) {
      mousePosXFinal = i;
      break;
    }
  }
  //
  // search mousePosYFinal
  for (int i = 0; i < height; i += 50) {
    if (mouseY<=i+50) {
      mousePosYFinal = i;
      break;
    }
  }

  // reset 
  startUp=true; 
  amt=0;
  i=0;

  float dist1 = dist(mousePosX, mousePosY, mousePosXFinal, mousePosYFinal); 
  println(dist1);
  initalDist1=dist1;
}
//

```

---

<div class="post-metadata">

### Author: ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)
#### Post date: [November 3, 2019, 11:09pm UTC](https://discourse.processing.org/t/rotation-and-easing/5704/19 "2019-11-03T23:09:14Z")

</div>

Here is a another example:

> [@Ball moving - Linear and Cosinusoidal](https://discourse.processing.org/t/ball-moving-linear-and-cosinusoidal/15209):
>
> A ball moving between points; overlapping linear and cosinusoidal movement. I was cleaning up some old code and sharing a minimal version; I wrote some of the functions as an exercise. [test] // GLV // 2019-11-3 // Plots a trajectory between 2 points. // Linear speed and cosinusoidal modulation of speed. PVector m1, m2, p1, p2, mid; PVector v1, v2, v3; PVector [] plot = new PVector[10000]; float theta; float rad = 20; boolean update = false; boolean save = false; boolean toggle = false; i…

🙂
