4

Basically, the issue I am trying to solve is that of "zooming round a point in a graphic, so that this point stays put on the display".

First, here is how I display the curve within a rectangle on screen :

The curve has xmin, xmax, ymin and ymax coordinates and so does the rectangle. Displaying the curve is just a matter of computing an affine transformation (xa, xb, ya, yb) that will map any point of the curve within xmin .. xmax ; ymin .. ymax boundaries to that of the rectangle. Let P(x,y) be a point of the curve. The corresponding pixel to light has screen coordinates (x * xa + xb , y * ya + yb).

Now, I have tried to solve the zoom problem using different approaches. The latest one (the one that gives the best results) is obtained by considering that :

– Zooming is achieved by actually narrowing xmin ... xmax and ymin .. ymax coordinates of the curve, since the size of the display rectangle stays constant.

Thus, if I want to perform a x2 zoom of a factor f, I can proceed in two steps :

  1. Keep the origin (xmin, ymin) and scale the width giving the new boundaries to display :

new_xmin = xmin

new_xmax = ((xmax - xmin) / f) + xmin

new_ymin = ymin

new_ymax = ((ymax - ymin) / f) + ymin

That achieves the zoom, keeping the origin stable. That's not what I want. I want to keep a point P(px, py) belonging to the initial range at the same place in the display rectangle. So I need to translate these coordinates by kx, ky to keep a point P(x,y) that was inside the first boundaries at the same place of the screen. Here is what I came up with :

kx = (px - xmin) * f - (px - xmin) / (xmax - xmin)
ky = (py - ymin) * f - (py - ymin) / (ymax - ymin)

So, the new coordinates to display are :

new_xmin = xmin - kx
new_xmax = ((xmax - xmin) / f) + xmin - kx    
new_ymin = ymin - ky
new_ymax = ((ymax - ymin) / f) + ymin -ky

That's close, but it doesn't work. kx and ky are too small and zooming mostly look like it's happening around xmin,ymin.

Any suggestions ? Thanks for enlightinig me...

EDIT: In this approach I do not take into account the width or height of the display rectangle. Is it a mistake? I do not feel like it is of importance since it does not change.

Adeline
  • 143

2 Answers2

2

When you have a “do some transformation centered on an arbitrary point” problem to solve, a generally fruitful approach is to break it down into three steps: translate the origin to the point, apply the transformation, and then translate back. In most cases, applying the required transformation at the origin instead of some other point is relatively straightforward.

Since your question is related to computer graphics, I’m going to describe a solution in terms of transformation matrices and homogeneous coordinates. If you’re unfamiliar with them, you can find the basics here and other places on the Web. I’ll use the common CG convention of representing points and vectors as tuples (row vectors), so that applying a transformation amounts to right-multiplication by a matrix.

The current image-to-screen transformation that you describe amounts to a dilation (scaling) followed by a translation, represented by the matrix $$M=\begin{bmatrix}x_a&0&0\\0&y_a&0\\x_b&y_b&1\end{bmatrix}.$$ The last column of all the matrices will be the same, so I’ll omit it in what follows to save space. We can find the transformation after zooming by calculating a matrix which performs the zoom in screen space and then concatenating (composing) that with the current transform to get an updated image-to-screen transform.

The screen-space zoom is easy to construct if we break it down as I suggested at the top. Let $(x_0,y_0)$ be the fixed point, and $s_x$, $s_y$ the horizontal and vertical zoom factors. The zoom matrix is then $$Z=\begin{bmatrix}1&0\\0&1\\-x_0&-y_0\end{bmatrix}\begin{bmatrix}s_x&0\\0&s_y\\0&0\end{bmatrix}\begin{bmatrix}1&0\\0&1\\x_0&y_0\end{bmatrix}=\begin{bmatrix}s_x&0\\0&s_y\\(1-s_x)x_0&(1-s_y)y_0\end{bmatrix}.$$ You can verify that $(x_0,y_0,1)Z=(x_0,y_0,1)$ as required. We then update the current image-to-screen transform by concatenating the zoom matrix to it—i.e., multiply them together: $$MZ=\begin{bmatrix}x_a&0\\0&y_a\\x_b&y_b\end{bmatrix}\begin{bmatrix}s_x&0\\0&s_y\\(1-s_x)x_0&(1-s_y)y_0\end{bmatrix}=\begin{bmatrix}s_xx_a&0\\0&s_yy_a\\s_x(x_b-x_0)+x_0&s_y(y_b-y_0)+y_0\end{bmatrix}.$$ This matrix corresponds to the mapping $$(x,y)\mapsto(s_xx_ax+s_x(x_b-x_0)+x_0,s_yy_ay+s_y(y_b-y_0)+y_0).$$ This is also a dilation (with the products of the original scale and zoom factors as the new scale factors) plus a translation, so the result is plausible. As a further check, the point in the image space that corresponds to $(x_0,y_0)$ before zooming is $(x_0,y_0,1)M^{-1}$. After zooming, this point gets mapped to $(x_0,y_0,1)M^{-1}MZ=(x_0,y_0,1)Z=(x_0,y_0,1)$, so it stays in the same spot on the screen.

Per Christian Blatter’s suggestion, you can animate the zoom by multiplying each scale factor by a parameter $t_k$ that ranges from $1/s_k$ to $1$. You can play around with different curves for $t$ to create various animation effects.

If you use one of the common CG libraries instead of managing the graphics yourself, you’ll find that all of these transformation manipulations are available as primitives in the API.

Postscript: Those matrix multiplications might look daunting, but they represent a cascade of simple operations that can be performed directly on the image-to-screen mapping, thusly: $$\begin{array}{ccl} x_ax+x_b & y_ax+y_b & \\ x_ax+x_b-x_0 & y_ax+y_b-y_0 & \text{translate by }(-x_0,-y_0) \\ s_x(x_ax+x_b-x_0) & s_y(y_ax+y_b-y_0) & \text{scale by }(s_x,s_y) \\ s_x(x_ax+x_b-x_0)+x_0 & s_y(y_ax+y_b-y_0)+y_0 & \text{translate by }(x_0,y_0) \end{array}$$ A bit of rearrangement yields the same expressions as above.

amd
  • 53,693
1

The problem can be dealt with for the $x$- and $y$-direction separately. In both directions you are given two nested compact intervals $$[u,v]\subset[a,b]\subset{\mathbb R}$$ with $v-u>0$, and want a bijective affine map $f:\>[u,v]\to[a,b]$. There is a unique such map $$f(x):={v-x\over v-u} a+{x-u\over v-u} b\ .$$ This map has a zoom factor $\sigma:={\displaystyle{b-a\over v-u}}\geq1$. If $\sigma>1$ there is a unique fixed point $$\xi:={(b-v)u+(u-a)v\over(b-v)+(u-a)}\ \in[u,v]\ .$$ If you want to realize the zoom live (i.e., in real time $t$) with center point $\xi$ you can write $$F(x,t)=\xi+\sigma(x-\xi)\qquad(1\leq t\leq \sigma)\ .$$ Then $F(x,1)=x$, and $F(x,\sigma)=f(x)$.

Note that the resulting zoom factors for the $x$- and the $y$-direction are different. If this is not desired additional measures have to be taken.

  • Christian, thank you for your reply. Thought it is well beyond anything I can understand (what is [u,v] ? the union symbol, the := operator ? The compactness ? and so on...) it actually made me think of something : kx = xmin - px + (px - xmin)/f instead of kx = (px - xmin) * f - (px - xmin) / (xmax - xmin) because there is no reason for kx to be dependent on xmax... That' what I was looking for. Thanks for your help. – Adeline Aug 05 '16 at 18:16
  • I think you should get accustomed to standard mathematical notation, instead of living solely in the world of pseudocode. The "operator" $:=$ means that the symbol on the side with the $:$ is defined to be the value of the expression on the other side of the $=$. – Don't accept an answer that you don't understand at least 90%! – Christian Blatter Aug 05 '16 at 18:31