0
\$\begingroup\$

I'm trying to create a sort of "graphing calculator coordinate system" where you can zoom into a point by scrolling with the mouse wheel. I'm using javafx's transformation matrices (Affines) to keep track of scale and translation. I'm struggeling to come up with a function that allows me to zoom into a point when scrolling, it always comes out weird and moves the canvas in strange ways. This is what I have tried:

    double multiplier = event.getDeltaY() / 1000.0; //event.getDeltaY() = mousewheel scroll

    //event.getX() = mouseX, event.getY() = mouseY
    this.cam.move(new Point2D(-event.getX() * multiplier, -event.getY() * multiplier)); //calls Affine.appendTranslation
    this.cam.zoom(1 + multiplier); //calls Affine.appendScale

There is also Affine.prependScale and Affine.prependTranslation which adds scale / translation before existing operations. I'm not very good at matrix maths so if anyone knows a working zoom function please let me know.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I don't know javafx, but I can tell you the math.

An affine transformation is a linear transformation combined with a translation. e.g.

A(p) = | l11 l12 | * | p_x | + | t_x |
       | l21 l22 |   | p_y |   | t_y |

Usually, for simplicity, we use homogeneous coordinates, which allows to write the transformation as a single matrix product:

       | l11 l12 t_x |   | p_x |
A(p) = | l21 l22 t_y | * | p_y |
       |  0   0   1  |   |  1  |

Now suppose that A(c) = q and you want to zoom in such that the new transform A' keeps A'(c) = q. The linear zoom matrix is trivial:

       | z 0 0 |   | p_x |
Z(p) = | 0 z 0 | * | p_y |
       | 0 0 1 |   |  1  |

where z is the zoom factor. Notice that Z has one fixed point, (0, 0).

          | z 0 0 |   | 0 |   | z*0 + 0*0  + 0*1 |   | 0 |
Z(0, 0) = | 0 z 0 | * | 0 | = | 0*0 + z*0  + 0*1 | = | 0 |
          | 0 0 1 |   | 1 |   | 0*0 + 0*0  + 1*1 |   | 1 |

So basically, you want to combine A with a modified version of Z such that the fixed point is at q (if you place that modified Z in front of A) or c (if you place A in front of that modified Z).

To have a fixed point at q, simply translate so that q is sent to 0, zoom, then translate back.

Z' = T⁻¹ * Z * T

where T is the relevant translation. Expanding the matrices, we have:

        | 1 0 q_x |   | z 0 0 |   | 1 0 -q_x |   | p_x |
Z'(p) = | 0 1 q_y | * | 0 z 0 | * | 0 1 -q_y | * | p_y |
        | 0 0  1  |   | 0 0 1 |   | 0 0   1  |   |  1  |

Notice that Z'(q) = q

Now you simply combine Z' with A:

A' = Z' * A

Now we can see that:

A'(c) = Z'(A(c)) = Z'(q) = q
\$\endgroup\$
0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.