Zooming and Panning headache

UPDATE: FINALLY I have a working code .... (further down is original post with glitchy code)

// working code    
float mx,my,ratio,xpt,ypt,xzt,yzt,swt,zoom;
void setup() {
 size(600,600);
  zoom=1.0;
  mx=width/60;
  my=mx*height/width;
  ratio=mx/my;
}
void draw() {
  scale(zoom);
  translate(xpt-xzt,ypt-yzt);
  background(128);
  grid(60,60/ratio);
}
void mouseDragged(){
  xpt-=(pmouseX-mouseX)/zoom;
  ypt-=(pmouseY-mouseY)/zoom;
}
void mouseWheel(MouseEvent event) {
  swt-=event.getCount();
  if (swt==0) {
    zoom=1.0;
  } else if (swt>=1 && swt<=10) {
    zoom=pow(2, swt);
  } else if (swt<=-1 && swt>=-10) {
    zoom=1/pow(2, abs(swt));
  }
  xzt=((zoom-1)*width/2)/zoom;
  yzt=((zoom-1)*height/2)/zoom;
  if(event.getCount()<=-1){
  xpt-=(mouseX-width/2)/zoom;
  ypt-=(mouseY-height/2)/zoom;
  } else {
  xpt+=(mouseX-width/2)/(pow(2, swt+1));
  ypt+=(mouseY-height/2)/(pow(2, swt+1));
  }
}
void grid(float x, float y) {
  stroke(0);
  for(int i = 0; i < x; i++){line(i*width/x,0,i*width/x,height);}
  for(int i = 0; i < y; i++){line(0,i*height/y,width,i*height/y);}
fill(#ff0000);rect(mx*10,mx*10,mx,mx);
fill(#ffff00);rect(mx*49,mx*10,mx,mx);
fill(#00ff00);rect(mx*10,mx*49,mx,mx);
fill(#0000ff);rect(mx*49,mx*49,mx,mx);
}

Original post I struggled with zoom for a long time and it's irritating and I'm about to give up.
First I was using variables instead of translate() or scale() because I didn't know they existed.
Just wanna zoom in on whatever I'm pointing the mouse at which sounds simple but yet it's zooming in somewhere else.
If don't pan, or only pan when at zoom 1.0 then it works as intended.
BUT if I pan at another zoom say 0.5 or 2.0 then zooming immediately becomes chaotic.
I just detached the issue in a separate sketch and tried using the transform functions, and yet it acts the exact same way.
Here is that sketch, problem must be somewhere between line 20 and 40

// non working original code
float mx,my,ratio; // not relevant for problem

float xpt; // translation
float ypt;
float xzt; // zoom translation
float yzt;
float swt; //scrollwheel ticks
float zoom = 1.0;

// setup not relevant
void setup() {
 size(600,600);
  mx=width/60;
  my=mx*height/width;
  ratio=mx/my;
}

// here starts the relevant part

void draw() {
  scale(zoom);
  translate(xpt-xzt,ypt-yzt);
  background(128);
  grid(60,60/ratio);
}
void mouseDragged(){
  xpt-=(pmouseX-mouseX)/zoom;
  ypt-=(pmouseY-mouseY)/zoom;
}
void mouseWheel(MouseEvent event) {
  swt-=event.getCount(); // swt = wheel ticks
  if (swt==0) {
    zoom=1.0;
  } else if (swt>=1 && swt<=10) {
    zoom=pow(2, swt);
  } else if (swt<=-1 && swt>=-10) {
    zoom=1/pow(2, abs(swt));
  }
  xzt=((zoom-1)*mouseX)/zoom;
  yzt=((zoom-1)*mouseY)/zoom;
}

// here ends the relevant part

void grid(float x, float y) {
  for(int i = 0; i < x; i++){line(i*width/x,0,i*width/x,height);}
  for(int i = 0; i < y; i++){line(0,i*height/y,width,i*height/y);}
fill(#ff0000);rect(mx*10,mx*10,mx,mx);
fill(#ffff00);rect(mx*49,mx*10,mx,mx);
fill(#00ff00);rect(mx*10,mx*49,mx,mx);
fill(#0000ff);rect(mx*49,mx*49,mx,mx);
fill(250);rect(xzt+mouseX/zoom-xpt-mx/2,yzt+mouseY/zoom-ypt-mx/2,mx,mx);
}

EDITED:

Answers

  • Maybe PeasyCam library can help you out: :-/
    http://MrFeinberg.com/peasycam/

  • Maybe PeasyCam library can help you out
    I don't think so

  • Answer ✓

    There was an attempt using a different approach in this previous post:
    https://forum.processing.org/two/discussion/20445/resize-sketch-window

    There is another recent post where they talk about having issues with scale: https://forum.processing.org/two/discussion/comment/88626/#Comment_88626 I think scaling might be happening in a different reference frame. Your situation is even more complex as you are managing translation and scaling on your main coordinates at the same time.

    There is one thing that could make things easier. If you tried to zoom in, instead of zooming in at the mouse position, you should zoom in with respect to the center of the sketch. The user is forced to ensure its point of interest is at the center of the screen. I still think the PGraphics method is more convenient or using one of the libraries available in Processing.

    One more thing. Are you aware of rectMode and imageMode? Working in a CENTER mode will go hand on hand with my suggested approach. Please check the reference to obtain more information about these modes.

    Kf

  • edited February 2017

    Thanks for the reply, unfortunately I don't think it solves the problem.
    (EDIT: zooming into the middle was a good idea after all)
    I found a working javascript example of what I'm trying to do.
    https://bl.ocks.org/mbostock/3680958
    I have done some trial and error and it behaves the same no irregardless of what point I'm trying to zoom into, corner, center, mouse, outside the screen.
    I wasn't aware of CENTER mode so haven't tried that. In the end I'm just going to be zooming in on elipsses though so would be surprised if that made any difference.

  • AFAIK you should translate before you scale. Try it, it may solve the problem.

  • edited February 2017

    There is one thing that could make things easier. If you tried to zoom in, instead of zooming in at the mouse position, you should zoom in with respect to the center of the sketch.

    I know I tried this before and it didn't work, but now it does :S

    float mx,my,ratio,xpt,ypt,xzt,yzt,swt,zoom;
    void setup() {
     size(600,600);
      zoom=1.0;
      mx=width/60;
      my=mx*height/width;
      ratio=mx/my;
    }
    void draw() {
      pushMatrix();
      scale(zoom);
      translate(xpt-xzt,ypt-yzt);
      background(128);
      grid(60,60/ratio);
      popMatrix();
      stroke(255);
      line(0,height/2,width,height/2);
      line(width/2,0,width/2,height);
    }
    void mouseDragged(){
      xpt-=(pmouseX-mouseX)/zoom;
      ypt-=(pmouseY-mouseY)/zoom;
    }
    void mouseWheel(MouseEvent event) {
      swt-=event.getCount();
      if (swt==0) {
        zoom=1.0;
      } else if (swt>=1 && swt<=10) {
        zoom=pow(2, swt);
      } else if (swt<=-1 && swt>=-10) {
        zoom=1/pow(2, abs(swt));
      }
      xzt=((zoom-1)*width/2)/zoom;
      yzt=((zoom-1)*height/2)/zoom;
      if(event.getCount()<=-1){
      xpt-=(mouseX-width/2)/zoom;
      ypt-=(mouseY-height/2)/zoom;
      } else {
      // align to mouse when zooming out
      }
    }
    void grid(float x, float y) {
      stroke(0);
      for(int i = 0; i < x; i++){line(i*width/x,0,i*width/x,height);}
      for(int i = 0; i < y; i++){line(0,i*height/y,width,i*height/y);}
    fill(#ff0000);rect(mx*10,mx*10,mx,mx);
    fill(#ffff00);rect(mx*49,mx*10,mx,mx);
    fill(#00ff00);rect(mx*10,mx*49,mx,mx);
    fill(#0000ff);rect(mx*49,mx*49,mx,mx);
    }
    

    EDIT: I can now zoom IN to the mouse, and zoom OUT from the center,
    just have to solve zooming out from the mouse and it's done

  • It sounds like you want the camera to track (or truck) and pan as it might in for example a first-person shooter. If so, have you looked at the QueasyCam library?

  • edited February 2017

    AFAIK you should translate before you scale. Try it, it may solve the problem.

    I didn't know that. Now that I wrote the zooming things using scale first obviously it's glitching when I changed the order afterwards.

    void draw() {
      pushMatrix();
      translate(xpt-xzt,ypt-yzt);
      scale(zoom);
      background(128);
      grid(60,60/ratio);
      popMatrix();
      stroke(255);
      line(0,height/2,width,height/2);
      line(width/2,0,width/2,height);
    }
    void mouseDragged(){
      xpt-=(pmouseX-mouseX);
      ypt-=(pmouseY-mouseY);
    }
    void mouseWheel(MouseEvent event) {
      swt-=event.getCount();
      if (swt==0) {
        zoom=1.0;
      } else if (swt>=1 && swt<=10) {
        zoom=pow(2, swt);
      } else if (swt<=-1 && swt>=-10) {
        zoom=1/pow(2, abs(swt));
      }
      xzt=((zoom-1)*(-xpt+width/2));
      yzt=((zoom-1)*(-ypt+height/2));
      if(event.getCount()<=-1){
      xpt-=(mouseX-width/2)/zoom;
      ypt-=(mouseY-height/2)/zoom;
      } else {
      // align to mouse wheen zooming out
      }
    }
    
  • It sounds like you want the camera to track (or truck) and pan as it might in for example a first-person shooter. If so, have you looked at the QueasyCam library?

    The same as gotoloop said I assume.
    No I am not using any libraries for anything, I don't wan't to do 3D things and I'm afraid it will zoom by moving the camera in Z-coordinate and then I have no idea where the mouse is. So it seems like a very complicated way to solve the problem to learn libraries and do 3D things when I'we gotten close to solving it with translate and scale.

  • Transformation order matters. In general, there is always an order of transformations that will make one's life easier. Always.

    Considering your original code, you accounted for the order (or attempted to) by applying the zoom factor in the right places (yes... you did more work!) The challenge I see with your code is that coupling scaling and mouse pointer position is not straight forward. I think I can make it work if I figure how the scaling changes the reference coordinates. Maybe the problem could be simply solved by calling an extra translation or could be more convoluted if the scaling transformation does not obey the imageMode's current state. This last is a concern (think more like to keep in mind) because there are functions in Processing that will neglect the imageMode parameter.

    There is another point to consider. If you zoom in when your mouse pointer is not in the center of the sketch (think like your mouse pointer toward one of the corners of your sketch), then after you start zooming, your point of interest will be out of the zoomed-in window unless you shift the center of the sketch to your mouse pointer's position. Since you are including panning in your application, then I would consider your post be solved if you do the zooming based on the center of the sketch. I believe that is exactly what most libraries do like peasycam or proscene.

    Kf

  • edited February 2017

    Zooming based on center ✓
    Zooming in based on mouse ✓
    Zooming out based on mouse ✘
    Understanding the problem ✘
    I feel like it's much closer to being solved but it will be hard to work with this mess.
    Anyways it doesn't feel so hopeless now, thanks for your help and patience

  • The same as gotoloop said I assume.

    No, they are not the same.

    1. PeasyCam is a library that centers on a single point and provides easy rotation of objects around that point (e.g. a globe) with no gimbal lock.
    2. QueasyCam is a library that provides a first-person track-and-pan interface to a moving camera.

    But if you don't want to do libraries or use 3D then neither is appropriate for you.

  • Zooming out based on mouse ✓
    It was not straightforward to solve, trial-and-errored until it worked.
    Updated the top post with the working code.
    It's a bit messy but it works.

  • First of all, thank you very much for the solution that I was looking for a long time! It's fast and compact. Very good work!

    Could you please share your thoughts about how the code is working? I understand that it was done mostly by trial-and-error, but still, maybe there is at least some background that helped you (an article or book, maybe)?

  • @Samuil9999 -- for ongoing discussions, you may also want to try the new forum: http://discourse.processing.org

Sign In or Register to comment.