Rotate and zoom question

Hi everyone,

I’m trying to zoom in on a sphere. Instead of zooming in from the center I would like to zoom in such a way that the red square stays in the yellow ellipse.

What would be a good way to achieve this do you think?

float r = 400;

void setup() {
  size(800, 800, P3D);
  smooth();
}

void draw() {
  background(0);
  ortho();
  translate(width/2, height/2);

  float scaler = map(mouseY, 0, height, 1, 1.5);
  
  //draw sphere with red box
  pushMatrix();
  scale(scaler);
  rotateX(-.7);
  //how should I rotate back here to correct for zoom
  //so that the red box stays within the yellow ellipse?
  noFill();
  strokeWeight(1);
  fill(128);
  stroke(255);
  sphere(r);
  strokeWeight(10);
  noStroke();
  fill(255, 0, 0);
  translate(0, 0, r);
  box(20);
  popMatrix();

  //draw yellow circle
  hint(DISABLE_DEPTH_TEST);
  rotateX(-.7);
  translate(0, 0, r);
  noFill();
  strokeWeight(2);
  stroke(255,255,0);
  ellipse(0, 0, 40, 40);
  hint(ENABLE_DEPTH_TEST);
}
1 Like

Hi Rick,

I think, below is a solution of what you want to achieve. This might not be the only solution and might also be optimized somehow.

float r = 400;

void setup() {
  size(800, 800, P3D);
  smooth();
}

void draw() {
  background(0);
  ortho();
  translate(width/2, height/2);

  float scaler = map(mouseY, 0, height, 1, 1.5);
  
  // calculate screen position of the red box
  pushMatrix();
  scale(scaler);
  rotateX(-.7);
  translate(0, 0, r);
  float redY = screenY(0, 0, 0);
  popMatrix();

  // calculate screen position of yellow circle
  pushMatrix();
  rotateX(-.7);
  translate(0, 0, r);
  float yellowY = screenY(0, 0, 0);
  popMatrix();

  float dy = yellowY - redY;
  
  //draw sphere with red box
  pushMatrix();
  translate(0, dy, 0);  // move the sphere 
  scale(scaler);
  rotateX(-.7);
  //how should I rotate back here to correct for zoom
  //so that the red box stays within the yellow ellipse?
  noFill();
  strokeWeight(1);
  fill(128);
  stroke(255);
  sphere(r);
  strokeWeight(10);
  noStroke();
  fill(255, 0, 0);
  translate(0, 0, r);
  box(20);
  popMatrix();

  //draw yellow circle
  hint(DISABLE_DEPTH_TEST);
  rotateX(-.7);
  translate(0, 0, r);
  noFill();
  strokeWeight(2);
  stroke(255,255,0);
  ellipse(0, 0, 40, 40);
  hint(ENABLE_DEPTH_TEST);
}

2 Likes

I assume the red square is a position on the sphere and its 3D coordinates are [rx, ry, rz] if my assumption is correct then this might work

  1. translate(width/2, height/2);
  2. Get the screen position with screenX(rx, ry, rz) and screenY(rx, ry, rz)
  3. translate to the calculated position
  4. scale the screen
  5. draw the sphere

You might have to play with the translation and scaling in steps 3 & 4

2 Likes

Hi @bohnacker and @quark,

Thank you so much for your help. It works! Here is my updated example where you can see it also working for a moving target (mouse on sphere)

Here’s the updated code:

float scaler = 1;
float r = 400;

void setup() {
  size(800, 800, P3D);
  smooth();
}

void draw() {
  background(0);
  ortho();
  translate(width/2, height/2);

  //mouse on sphere
  PVector p = new PVector(mouseX-width/2,mouseY-height/2);
  p.z = sqrt(r*r - p.mag());

  //calculate screen position of the mouse in scaled and unscaled mode
  pushMatrix();
  PVector unscaled = new PVector(screenX(p.x, p.y, p.z), screenY(p.x, p.y, p.z));
  scale(scaler);
  PVector scaled = new PVector(screenX(p.x, p.y, p.z), screenY(p.x, p.y, p.z));
  popMatrix();
  PVector delta = unscaled.sub(scaled);
  
  //draw sphere and mouse on sphere
  pushMatrix();
  translate(delta.x, delta.y, 0); 
  scale(scaler);
  noFill();
  stroke(255);
  strokeWeight(1);
  sphere(r);
  noStroke();
  fill(255, 0, 0);
  translate(p.x, p.y, p.z);
  box(20);
  popMatrix();
  
  saveFrame();
}

void mouseWheel(MouseEvent event) {
  //zoom factor needs to be between about 0.99 and 1.01 to be able to multiply so add 1
  scaler = constrain(scaler * (-event.getCount()*.01f + 1.0f), 1, 1.7);
}
1 Like