PattaFeuFeu
PattaFeuFeu

Reputation: 1835

“Rotate” and “translate” in processing give me headaches

As a small homework to get into Processing, I had to write some code to get the following: task

Using

public void setup() {
   size(300,200);
   noFill();
   rect(100, 20, 40, 80);
   ellipseMode(CENTER);
   fill(#000000);
   ellipse(width/2, height/2, 5,5);
   
   noFill();
   translate(width/2, height/2);
   rotate(radians(65));
   rect(-20, -40, 40, 80);
}
public void draw() {
}

this worked very good, so far. But I don’t like that I had to change the coordinates inside of the bottom rect instruction in order to get the rotation right. I know that by rotating you don’t rotate single elements but in fact the whole coordinate system. What I don’t know is which values to put into the translate instruction to have the output be like in the picture above while also still using the same coordinates within the rect command.

The task is already done with the code I used, I just don’t like it too much. So this isn’t mere asking for somebody else doing my homework but pure interest.

EDIT: More generalised attempt of a question: How do I know which values to pit into translate before rotate to get whatever result I want? Is there a way to calculate them? For sure, it’s not just trying out, is it?

Upvotes: 2

Views: 19847

Answers (3)

JAMESSTONEco
JAMESSTONEco

Reputation: 2051

A lot of the confusion in processing is the coordinate system. In Processing the origin (0,0) is at the top left of the screen and only positive coordinates display on the screen. The very common workaround for this is to call:

translate(width/2, height/2);

at the beginning of your void draw() method. That way 0,0 is now at the center of the sketch, and any subsequent methods called such as rotate(radians(65)) will take action from the center of the sketch.

This is also good because sketches that use the P3D or OPENGL renderer often call translate to change the coordinate system into something that is easier to use. For example an object at 0,0 or 0,0,0 is at the center and it makes it easier to orbit the camera around the object or have the object rotate around its center.

another popular way of drawing objects would be to set the origin as above and instead of giving the coordinates of each object, i.e. rect(-100, -50, 50, 50) is to use popMatrix() and pushMatrix before a translate before drawing each object at 0,0 as illustrated below:

translate(width/2, height/2);
pushMatrix();
  translate(-100, -50);
  rect(0,0,50,50);
popMatrix();

This is a good approach to use in a 2d renderer if you think you might move to 3d renderer eventually, because you can easily replace rect() with box() or sphere() or create your own method or object that draws geometry assuming the origin is at 0,0.

If you replace the x and y coordinates with variables or iterate through an array in a for loop it becomes very easy to draw hundreds or thousands of shapes in either 2d or 3d with minimal effort and minimal rewriting of the code.


update: added clarification for the original poster, per their comment.


I have changed the problem slightly to show you how I would approach this. I am showing the translate / rotate method I described above using push and pop matrix. I am just guessing at the values, but if you want something pixel accurate you can take measurements in an image editing program like photoshop or preview.

rect1

translate(180, 150);
rect(0, 0, 180, 80);

rect2

translate(185, 170);
rotate(radians(65));
rect(0, 0, 180, 80);

ellipse

translate(180, 250);
ellipse(0, 0, 8, 8);

Putting it all together with pushMatrix() and popMatrix().

void setup(){
  size(400,400);
}

void draw(){
  // rect1
  noFill();
  pushMatrix();
    translate(180, 150);
    rect(0, 0, 180, 80);
  popMatrix();
  // rect2
  pushMatrix();
    translate(185, 170);
    rotate(radians(65));
    rect(0, 0, 180, 80);
  popMatrix();
  // ellipse
  fill(0);
  pushMatrix();
    translate(180, 250);
    ellipse(0, 0, 8, 8);
  popMatrix();
}

Upvotes: 6

v.k.
v.k.

Reputation: 2854

in my particular example, know how to translate and rotate to get the result in the picture without changing the rectangle coordinates?

Well, you need to draw at origin to use rotate properly, so you are just dealing with the origin of the rect... As it is in your code, the default, the origin is the upper left corner, so you made an off set (from (0,0)) to draw it's centre, not the corner, at coordinate(0,0), then rotate by the middle. Well done. It is not coincidence that the values you found was minus half rect width(-20) and minus half rect height(-40). If you change to rectMode(CENTER) than you can just draw at (0,0). The same applies to translate, you can just translate to the desired point, the center of the screen, where there is the ellipse. What is done using half width and half height...

look:

public void setup() {
  size(300, 200);
  smooth();
  ellipseMode(CENTER);
  rectMode(CENTER);
  noFill();
  // here converting the coordinates to work with CENTER mode
  //could have changed the rect mode just after this
  // but i kept as an illustration
  int rwidth = 40;
  int rheight = 80;
  int xpos = 100 + rwidth/2;
  int ypos = height/2 - rheight/2 ;

  rect(xpos, ypos, rwidth, rheight);

  fill(#000000);
  ellipse(width/2, height/2, 5, 5);

  noFill();
  pushMatrix();

  translate(width/2, height/2);

  //draw at origin gray
  stroke(150);
  rect(0, 0, 40, 80);
  // then rotate
  rotate(radians(65));
  // draw again black
  stroke(0);
  rect(0, 0, 40, 80);

  popMatrix();


  // here using the cordinates calculated before as a translate value 
  // we draw at origin, but it appears at same place
  stroke(230,230,100);
  // a bit to the left...
  translate(xpos-2, ypos-2);

  rect(0, 0, 40, 80);

}

Upvotes: 3

v.k.
v.k.

Reputation: 2854

Rotation is aways applied to origin point (0,0), so you want to draw your axis for rotating at origin. Or move the coordinate system origin, to your axis. It is indeed confusing. When using transformations I tend to draw at origin always. Try this to see if it makes things more clear... or less :) Also there is push/popMatrix() to control the scope of transformations...

public void setup() {
  size(300, 380);
  smooth();
}
public void draw() {
  background(0);
  stroke(255);
  //use push/pop Matrix to control scope of translate and rotate
  pushMatrix();
  //move coordinates system origin to center of screen
  translate(width/2, height/2);
  // rotate with origin as axis
  rotate(radians(mouseY));
  //draw at origin (now temp moved to center of screen)
  // white line 
  line(0, 0, 150, 0);
  // here all coordinate system is back to normal
  popMatrix();

  //draw with normal system red line at origin
  stroke(255, 0, 0);
  line(0, 0, 150, 0);

    //draw with normal system blue line at centre
  stroke(0, 0, 255);
  line(width/2, height/2, width/2 + 150, height/2);
}

Upvotes: 3

Related Questions