Change of the rotation origin of drawn object

I’m learning about metods of moving objects in proccesing and I tried to make object to act like a tank. The problem is, in order to do so, i want it to rotate around one caterpillar while the other is working and vice versa. I know that the key recognition isn’t made in the best possible way. I was trying to change the origin by translate function but it moves my tank left or right and the center point is in the same position. I can’t find answer anywhere so here i am. I hope that my intention is clear enought, here is my code:

PVector pos = new PVector(0,0);
float rotateAngle = 180;

int[] colorOfCaterpillarOFF = {188, 77, 82};
int[] colorOfCaterpillarON = {226, 118, 122};
int[] colorOfCaterpillar_L = {188, 77, 82};
int[] colorOfCaterpillar_R = {188, 77, 82};

void setup(){
 size(800,800); 
 rectMode(CENTER);
}

void draw(){
 background(255,255,255);
 translate(width/2,height/2);
 stroke(125, 132, 142);
 line(0,-400,0, 400);
 line(-400,0,400,0);
 noStroke();  // cross lines in background
 
 translate(pos.x,pos.y);
 keyRecognition();
 rotate(radians(rotateAngle));
 drawTank();
  
}

void keyRecognition(){
        if(keyPressed && key=='d'){
            rotateAngle++;
             colorOfCaterpillar_R = colorOfCaterpillarON; // turning right
            translate(-34,0);
        } else if(keyPressed && key=='a'){
            rotateAngle--;
            colorOfCaterpillar_L = colorOfCaterpillarON; // turning left
            translate(34,0);
        }else if(keyPressed && key=='w'){
            pos.add(PVector.fromAngle(radians(rotateAngle+90)));
            colorOfCaterpillar_R = colorOfCaterpillarON;
            colorOfCaterpillar_L = colorOfCaterpillarON; //going straight
        }else if(keyPressed && key=='s'){
            pos.add(PVector.fromAngle(radians(rotateAngle+90)).mult(-1));
            colorOfCaterpillar_R = colorOfCaterpillarON;
            colorOfCaterpillar_L = colorOfCaterpillarON; // going backwards
        } else {
          colorOfCaterpillar_R = colorOfCaterpillarOFF;
          colorOfCaterpillar_L = colorOfCaterpillarOFF; // standing still
        }
    }
    
    void drawTank(){
        fill(27, 153, 73); // color of tanks body
        rect(0,0,50,80, 5,5,5,5); // tanks body
        fill(colorOfCaterpillar_L[0], colorOfCaterpillar_L[1], colorOfCaterpillar_L[2]);
        rect(-34,0,15,75,5,5,5,5);// caterpillars of the tank // left
        fill(colorOfCaterpillar_R[0], colorOfCaterpillar_R[1], colorOfCaterpillar_R[2]);
        rect(34,0,15,75,5,5,5,5); // right caterpillar
        fill(72, 122, 15);
        rect(0,20,30,20,5,5,5,5);
    }
1 Like

Hi bugaj,

You need to realize 2 things:

  • The order in which you call translate() and rotate() are really important.
  • Rotate() rotates everything around the point (0, 0)

Consider this simple sketch:

float angle;

void setup() {
  size(500, 500);
  angle = 0;
}

void draw() {
  background(20);
  fill(200, 20, 20);
  
  translate(width/2, height/2);
  rotate(angle);
  
  rect(-50, -50, 100, 100);
}

void keyPressed() {
  if (keyCode == 37) {
    angle -= 0.01;
  } else if (keyCode == 39) {
    angle += 0.01;
  }
}

It simply draws a rectangle and with the right and left arrows you can rotate it around its center.

Now just inverse the rotate() and translate() function so the draw() function is like the following:

void draw() {
  background(20);
  fill(200, 20, 20);
  
  rotate(angle);
  translate(width/2, height/2);
  
  rect(-50, -50, 100, 100);
}

See how it rotates around the point (0, 0) now? For me it makes more sense to think that the operations are applied from bottom to top. In the first example, you draw the shape, you rotate it and then your translate it. In the second, you draw the shape, you translate it and then your rotate it.

Now try drawing the rectangle first and then apply a translation and a rotation like so:

void draw() {
  background(20);
  fill(200, 20, 20);
  
  rect(-50, -50, 100, 100);
  
  rotate(angle);
  translate(width/2, height/2);
}

As you can see nothing happen since only things that are drawn after the transformations are affected by it.

So now, to get back to your problem what you should do is as follow:

  • Translate your tank to so the center of the caterpillar correspond to (0, 0)
  • rotate your tank
  • translate back to the original position (aka the center of your tank is at (0, 0)) <-- I think this is what you are missing
  • translate to the center of the screen

To illustrate it with the cube, if you want to rotate it from it’s bottom right corner the draw() function would become:

void draw() {
  background(20);
  fill(200, 20, 20);

  translate(width/2, height/2);
  translate(50, 50);
  rotate(angle/2);
  translate(-50, -50);

  rect(-50, -50, 100, 100);
}
3 Likes

Thank you very much for this great answer, I woudn’t figure this out by myself, but after doing as you said i notice that there is another problem (I think i did as you said). The center of tank isnt changing while turning so it gets back where it was after i stop holding key on keyboard.
I was trying to compersate this by making another vector which was astimated course of the center of tank (I coudn’t make it to be proper circle so it’s a rectangle) but it still don’t work as it should after i turn in the other way. Is there any way to calculate center point while turning and simply add it to position so tank stays here after im done turning? Here is what i added after your reply:

 if(turnRight){
   translate(-34,0);
 } else if(turnLeft){
   translate(34,0);
 }

 drawTank();
 
 turnLeft = false;
 turnRight = false;

TurnRight and TurnLeft is true when I’m turning. And here is what it looks like after i failed to make tank stay where it should after turning.

PVector pos = new PVector(0,0);
PVector posChange = new PVector(0,0); // What to add to the position after rotation so the center of the tank is where it should
float rotateAngle = 0;
float rotateAngle_2 = 0;

boolean turnLeft = false;
boolean turnRight = false;

int[] colorOfCaterpillarOFF = {188, 77, 82};
int[] colorOfCaterpillarON = {226, 118, 122};
int[] colorOfCaterpillar_L = {188, 77, 82};
int[] colorOfCaterpillar_R = {188, 77, 82};

PGraphics canvas;

void setup(){
 size(800,800); 
 rectMode(CENTER);
}

void draw(){
 background(255,255,255);
 translate(width/2,height/2);
 stroke(125, 132, 142);
 line(0,-400,0, 400);
 line(-400,0,400,0);
 noStroke();  // cross lines in background
 
 
 translate(pos.x,pos.y);
 keyRecognition();
 rotate(radians(rotateAngle));
 
 calculatePosChange();
 
 rotateAngle%=360;
 rotateAngle_2 = rotateAngle;
 

 
 
 
 translate(-1*posChange.x,-1*posChange.y);
 println("rotateAngle: " + rotateAngle);
 println("PosChange: (" + posChange.x+ "," + posChange.y + ")");
 println("Pos of the center: (" + (posChange.x+pos.x) + "," + (-1*(posChange.y+pos.y)) + ")" );

 drawTank();
 

}

void calculatePosChange(){
   if(turnRight){
     if(rotateAngle<=90){
     posChange = new PVector(map(rotateAngle_2,0,90,0,34),map(rotateAngle_2,0,90,0,34));
   } else if (rotateAngle <=180){
     posChange = new PVector(map(rotateAngle_2,90,180,34,68),map(rotateAngle_2,90,180,34,0));
   } else if (rotateAngle <=240){
     posChange = new PVector(map(rotateAngle_2,180,240,68,34),map(rotateAngle_2,180,240,0,-34));
   } else if (rotateAngle <=360){
     posChange = new PVector(map(rotateAngle_2,240,360,34,0),map(rotateAngle_2,240,360,-34,0));
   }
    turnRight = false;
 } else if(turnLeft){
   if(rotateAngle>=-90){
     posChange = new PVector(map(rotateAngle_2,0,-90,0,-34),map(rotateAngle_2,0,-90,0,34));
   } else if(rotateAngle>=-180){
     posChange = new PVector(map(rotateAngle_2,-180,-90,-68,-34),map(rotateAngle_2,-180,-90,0,34));
   } else if(rotateAngle>=-240){
     posChange = new PVector(map(rotateAngle_2,-240,-180,-34,-68),map(rotateAngle_2,-240,-180,-34,0));
   } else if(rotateAngle>=-3360){
     posChange = new PVector(map(rotateAngle_2,-360,-240,-0,-34),map(rotateAngle_2,-360,-240,0,-34));
   }
  turnLeft = false;
 }
}


void keyRecognition(){
        if(keyPressed && key=='a'){
            rotateAngle--;
             colorOfCaterpillar_R = colorOfCaterpillarON; // turning left
            turnLeft = true;
        } else if(keyPressed && key=='d'){
            rotateAngle++;
            colorOfCaterpillar_L = colorOfCaterpillarON; // turning right
            turnRight = true;
        }else if(keyPressed && key=='s'){
            pos.add(PVector.fromAngle(radians(rotateAngle+90)));
            colorOfCaterpillar_R = colorOfCaterpillarON;
            colorOfCaterpillar_L = colorOfCaterpillarON; //going straight
        }else if(keyPressed && key=='w'){
            pos.add(PVector.fromAngle(radians(rotateAngle+90)).mult(-1));
            colorOfCaterpillar_R = colorOfCaterpillarON;
            colorOfCaterpillar_L = colorOfCaterpillarON; // going backwards
        } else {
          colorOfCaterpillar_R = colorOfCaterpillarOFF;
          colorOfCaterpillar_L = colorOfCaterpillarOFF; // standing still
        }
    }
    
    
    void drawTank(){
        fill(27, 153, 73); // color of tanks body
        rect(0,0,50,80, 5,5,5,5); // tanks body
        fill(colorOfCaterpillar_L[0], colorOfCaterpillar_L[1], colorOfCaterpillar_L[2]);
        rect(-34,0,15,75,5,5,5,5);// caterpillars of the tank // left
        fill(colorOfCaterpillar_R[0], colorOfCaterpillar_R[1], colorOfCaterpillar_R[2]);
        rect(34,0,15,75,5,5,5,5); // right caterpillar
        fill(72, 122, 15);
        rect(0,-20,30,20,5,5,5,5);
    }