Zooming onto an arbitrary point

Started by
4 comments, last by lifeformed 13 years, 2 months ago
I cannot for the life of me figure out this seemingly simple problem.

I'm trying to figure out how to zoom onto a 2D point, and reposition the camera accordingly.

Let's say my current screen space is this gray box, with the top left corner x1, y1. I want to zoom in on that red dot, at Fx, Fy, with zoom amount Z. The resulting screen space should be the blue rectangle. How do I find x2, y2?
uq3r7.png


Now I've been able to figure out the math of this. It should be:
x2 = x1 + Fx / Z
y2 = y1 + Fy / Z
Right? But it seems to fall apart when zooming out, or when I zoom in again. Zooming out still increases it, since Z is always a positive number. Zooming in multiple times has all sorts of issues.

This seems like a very basic operation, yet I've spent many frustrated hours trying to get it to work. My drawing code works fine. I can pan the image, and I can zoom onto point 0,0 without any issues. So theoretically, zooming onto point F would be the same as zooming onto point 0,0 and panning it to F, right?

Thanks for any help.
Advertisement
I solved this problem once, but I forgot it. I want to reimplement it today, so I'll come back with the results (by the way I think it depends on a lot of things, so maybe it won't be useful to you).

By the way, as I recall it took me 2 hours to figure it out, and I'm pretty good at maths and vector algebra.
Well, I've just solved it.

The solution depends on the setup: I zoom and pan with the projection matrix, so I guess our coordinate systems are different.

But the logic is very simple: when zooming around a point, everything "moves" along a ray originated from the zoom center. And the distance of points increases with the same ratio: the zoom ratio (new_zoom_value / old_zoom_value). The center of the triangle (which you need to alter) behaves in the same way.

[attachment=1199:zoom.JPG]

So something like:
new_view_center = zoom_center + zoom_ratio * (old_view_center - zoom_center)

The values (in my case) are in WORLD coordinates. So the mouse (if it's the zoom center) needs to be "unprojected".

I hope that helps.

EDITED an error.

I cannot for the life of me figure out this seemingly simple problem.

I'm trying to figure out how to zoom onto a 2D point, and reposition the camera accordingly.

Let's say my current screen space is this gray box, with the top left corner x1, y1. I want to zoom in on that red dot, at Fx, Fy, with zoom amount Z. The resulting screen space should be the blue rectangle. How do I find x2, y2?
uq3r7.png


Now I've been able to figure out the math of this. It should be:
x2 = x1 + Fx / Z
y2 = y1 + Fy / Z
Right? But it seems to fall apart when zooming out, or when I zoom in again. Zooming out still increases it, since Z is always a positive number. Zooming in multiple times has all sorts of issues.

This seems like a very basic operation, yet I've spent many frustrated hours trying to get it to work. My drawing code works fine. I can pan the image, and I can zoom onto point 0,0 without any issues. So theoretically, zooming onto point F would be the same as zooming onto point 0,0 and panning it to F, right?

Thanks for any help.


I haven't tested this, but you could try this.

ix1 = initial x top left
iy1 = initial y top left
ix2 = initial x bottom right
ix2 = initial y bottom right
Fx = Focus X
Fy = Focus Y
MaxZoomX = is the limit of the zoom
ZoomLevels = Max levels of zoom

new screen is (x1,y1) (x2,y2)
x1 = ix1 + ( Fx - ix1 )/ZoomLevels*z
y1 = iy1 + ( Fy - iy1 )/ZoomLevels*z
x2 = ix2 - ( ix2 - Fx )/ZoomLevels*z
y2 = iy2 - ( iy2 - Fy )/ZoomLevels*z
From the picture in the OP it seems me that the position of F should be fixed in the shown co-ordinate frame. Hence we're speaking of a scaling that happens uniformly in both dimensions but using an explicit reference point (that is the point that doesn't change its position due to the scaling). This is a standard problem and solved by making the fix point temporarily the origin, like so (written using row vectors):
F-1 * S * F
where F denotes the translation matrix build from [ Fx Fy ], S denotes the (uniform) scale matrix build from a scale factor s.

Writing this with components and applied to [ x1 y1 ] looks like
( x1 - Fx ) * s + Fx =: x2
( y1 - Fy ) * s + Fy =: y2

Using s==1 does obviously nothing, using 0<s<1 lets the co-ordinates "shrink" towards F, and using s>1 let them "grow" away from F. From here on a normalization can be done if needed. The new center (w.r.t. the original co-ordinate frame) can be computed simply by average of the upper left and lower right corners at any moment.

new_view_center = zoom_center + zoom_ratio * (old_view_center - zoom_center)


Yes, that's it! It works great now. The problem was I wasn't taking the ratio in account. I was just using the new value. This made subsequent zooms incorrect.

[font=arial, verdana, tahoma, sans-serif][size=2]

I haven't tested this, but you could try this.

ix1 = initial x top left
iy1 = initial y top left
ix2 = initial x bottom right
ix2 = initial y bottom right
Fx = Focus X
Fy = Focus Y
MaxZoomX = is the limit of the zoom
ZoomLevels = Max levels of zoom

new screen is (x1,y1) (x2,y2)
x1 = ix1 + ( Fx - ix1 )/ZoomLevels*z
y1 = iy1 + ( Fy - iy1 )/ZoomLevels*z
x2 = ix2 - ( ix2 - Fx )/ZoomLevels*z
y2 = iy2 - ( iy2 - Fy )/ZoomLevels*z


[font=arial, verdana, tahoma, sans-serif][size=2]The zooming system I used is based on a scaling factor, not zoom levels. I probably should have used zoom levels though, since a zoom level has information about the previous level, which is what I was missing and why szecs solution worked. Thanks![font=arial, verdana, tahoma, sans-serif][size=2]
[font=arial, verdana, tahoma, sans-serif][size=2]

From the picture in the OP it seems me that the position of F should be fixed in the shown co-ordinate frame. Hence we're speaking of a scaling that happens uniformly in both dimensions but using an explicit reference point (that is the point that doesn't change its position due to the scaling). This is a standard problem and solved by making the fix point temporarily the origin, like so (written using row vectors):
F-1 * S * F
where F denotes the translation matrix build from [ Fx Fy ], S denotes the (uniform) scale matrix build from a scale factor s.

Writing this with components and applied to [ x1 y1 ] looks like
( x1 - Fx ) * s + Fx =: x2
( y1 - Fy ) * s + Fy =: y2

Using s==1 does obviously nothing, using 0<s<1 lets the co-ordinates "shrink" towards F, and using s>1 let them "grow" away from F. From here on a normalization can be done if needed. The new center (w.r.t. the original co-ordinate frame) can be computed simply by average of the upper left and lower right corners at any moment.


That's a good idea: moving the zoom point to the origin and then moving it back post-zoom. Thanks for the tip.

This topic is closed to new replies.

Advertisement