Timothy Bowen
Timothy Bowen

Reputation: 73

Rotating text not the position of the text in processing

i am trying to make a clock and have all the numbers in the correct place but they are all rotated e.g. 6 is upside down whereas 12 is correct. is there anyway to rotate just the text not the position of the text?

my code is

push();
  textSize(48);
  for (int i = 1; i < 13; i++) {
    int offset = -15;
    if (str(i).length() == 2) {
      offset -= 14.5;
    }
    rotate(radians(30));
    text(i, offset, -350);
    //println(i*30);
  }
  pop();

Upvotes: 4

Views: 402

Answers (1)

George Profenza
George Profenza

Reputation: 51837

Without seeing the code my hunch is you use rotate(), but probably you don't use pushMatrix()/popMatrix(); to isolate the coordinate space to local one that can be temporarily rotated.

I recommend reading the 2D Transformations tutorial

transforms 2d tutorial image: a grid translated then rotated

As the tutorial mentions, the order of transformations matters:

size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
// global translation to center
translate(width / 2, height / 2);

int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for(int i = 0 ; i < hours; i++){
  // calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
  // remember this offset: it may come in handy when drawing clock handles ;)
  float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
  // isolate coordinate space
  pushMatrix();
    // rotate from global center by each hour angle
    rotate(angle);
    // translate from locally rotated center based on radius 
    translate(radius, 0);
    // undo local rotation so text is straight
    rotate(-angle);
    // render text
    text(i+1,0,0);
  // exit local coordinate system, back to global coordinates after this
  popMatrix();
}

Here is the same example with a helper function to help visualise the coordinate systems:

void setup() {
  size(300, 300);
  background(0);
  stroke(255);
  // center align text
  textAlign(CENTER);
  drawCoordinateSystem("1.original cooordinates",60, 255);
  // global translation to center
  translate(width / 2, height / 2);
  drawCoordinateSystem("2.global center",60, 64);
  

  int hours = 12;
  // an angle section (360/12 = 30 degrees), but in radians
  float angleIncrement = TWO_PI / hours;
  // distance from center
  float radius = 100;
  for (int i = 0; i < hours; i++) {
    // calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
    // remember this offset: it may come in handy when drawing clock handles ;)
    float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
    // isolate coordinate space
    pushMatrix();
      // rotate from global center by each hour angle
      rotate(angle);
      if(i == 0){
        drawCoordinateSystem("3.local+rotation",60, 127);
      }
      // translate from locally rotated center based on radius 
      translate(radius, 0);
      if(i == 0){
        drawCoordinateSystem("4.local+rot.+\ntrans.",60, 192);
      }
      // undo local rotation so text is straight
      rotate(-angle);
      if(i == 0){
        drawCoordinateSystem("\n5.prev.\n-rot.",60, 255);
      }
      // render text
      text(i+1, 0, 0);
    // exit local coordinate system, back to global coordinates after this
    popMatrix();
  }
}

void drawCoordinateSystem(String label, float size, float alpha){
  pushStyle();
  textAlign(LEFT);
  strokeWeight(3);
  // x axis
  stroke(192, 0, 0, alpha);
  line(0, 0, size, 0);
  // y axis
  stroke(0, 192, 0, alpha);
  line(0, 0, 0, size);
  text(label, 10, 15);
  popStyle();
}

coordinate systems visualised as red/green orthogonal lines

Note that the indent is not required for pushMatrix()/popMatrix(), it's more of a visual cue to aid when you read code to remember coordinate system nesting.

This is over the top and you won't need the code bellow, but hopefully it's a fun visualisation:

PImage screenshot;

String[] labels = {"1.original cooordinates","2.global center\ntranslate(width / 2, height / 2)",
                   "3.local+rotation\npushMatrix();\nrotate(angle)",
                   "4.local+rot.+\ntrans.\ntranslate(radius, 0)","5.previous-rot.\nrotate(-angle)",""};
PMatrix2D[] systems = new PMatrix2D[labels.length];
PMatrix2D lerpMatrix = new PMatrix2D();

void setup() {
  size(300, 300);
  background(0);
  stroke(255);
  // center align text
  textAlign(CENTER);
  // "1.original cooordinates"
  systems[0] = new PMatrix2D();
  // global translation to center
  translate(width / 2, height / 2);
  // "2.global center"
  systems[1] = systems[0].get();
  systems[1].translate(width / 2, height / 2);
  

  int hours = 12;
  // an angle section (360/12 = 30 degrees), but in radians
  float angleIncrement = TWO_PI / hours;
  // distance from center
  float radius = 100;
  for (int i = 0; i < hours; i++) {
    // calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
    // remember this offset: it may come in handy when drawing clock handles ;)
    float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
    // isolate coordinate space
    pushMatrix();
      // rotate from global center by each hour angle
      rotate(angle);
      if(i == 0){
        // "3.local+rotation"
        PMatrix2D local = new PMatrix2D();
        local.apply(systems[1]);
        local.rotate(angle);
        systems[2] = local.get();
      }
      // translate from locally rotated center based on radius 
      translate(radius, 0);
      if(i == 0){
        // "4.local+rot.+\ntrans."
        systems[3] = systems[2].get();
        systems[3].translate(radius,0);
      }
      // undo local rotation so text is straight
      rotate(-angle);
      if(i == 0){
        // "\n5.prev.\n-rot."
        systems[4] = systems[3].get();
        systems[4].rotate(-angle);
        systems[5] = systems[4];
      }
      // render text
      text(i+1, 0, 0);
    // exit local coordinate system, back to global coordinates after this
    popMatrix();
  }
  screenshot = get();
}

void draw(){
  image(screenshot,0, 0);
  animateCoordinateSystems();
  text("mouse mouse on X axis", width / 2, height - 12);
}

void animateCoordinateSystems(){
  float mapping = map(constrain(mouseX, 0, width), 0, width, 0.0, 1.0);
  float globalT = (float)(labels.length -1) * mapping;
  int index = (int)globalT;
  float localT = globalT - index;
  lerpMatrix(systems[index], systems[index+1], localT, lerpMatrix);
  pushMatrix();
  applyMatrix(lerpMatrix);
  drawCoordinateSystem(labels[index] + (labels[index+1].length() > 0 ? "\ntransitions to\n" + labels[index+1] : ""),60, 255);
  popMatrix();  
}

void lerpMatrix(PMatrix2D from, PMatrix2D to, float t, PMatrix2D result){
  result.m00 = lerp(from.m00, to.m00, t);
  result.m01 = lerp(from.m01, to.m01, t);
  result.m02 = lerp(from.m02, to.m02, t);
  result.m10 = lerp(from.m10, to.m10, t);
  result.m11 = lerp(from.m11, to.m11, t);
  result.m12 = lerp(from.m12, to.m12, t);
}


void drawCoordinateSystem(String label, float size, float alpha){
  pushStyle();
  textAlign(LEFT);
  strokeWeight(3);
  // x axis
  stroke(192, 0, 0, alpha);
  line(0, 0, size, 0);
  // y axis
  stroke(0, 192, 0, alpha);
  line(0, 0, 0, size);
  text(label, 10, 15);
  popStyle();
}

animated coordinate systems

Upvotes: 8

Related Questions