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

0
\$\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\$
1
  • \$\begingroup\$ That worked wonderfully, thank you so much \$\endgroup\$
    – user156844
    Oct 8, 2021 at 18:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .