Task
There are certain objects that need to be scaled, for example, a rectangle that should grow/shrink depending on mouse wheel rotation, while scaling should be done relative to a specified point, such as the mouse cursor position.
The complexity arises when the relative point changes: the mouse is moved - a new point.
Moving and scaling an object
- Move the object space in such a way that the scaling point is at the origin (0,0).
- Perform the actual transformation.
- Move the object space back - perform exactly the same transformation but in reverse, without considering the scaling factor.
Visual explanation
Zoom in relative to a point (4, 6) |
Zoom in relative to a point (3, 5) |
Implementation in Java
public class PointScale extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
final Graphics2D g2d = (Graphics2D) g;
final AffineTransform transform = new AffineTransform();
// Perform a shift of a point (0, 0)
transform.translate(point.x, point.y);
// Perform a zoom
transform.scale(zoom, zoom);
// Restore the position to its original state (0, 0) -> point
transform.translate(-point.x, -point.y);
// Apply all transformations
g2d.setTransform(transform);
}
}
Moving and scaling the rendering area
To perform a relative transformation, it's necessary to first execute the initial one, and then on top of it, the new one.
Since in this task we are changing the sizes and positions not of specific objects, but of the entire field, it's necessary to transform the field each time it's redrawn, as it resets to its original state every time.
Find the difference between the shift of the coordinate system of the previous state and the position of the cursor relative to the scaled coordinate system of the previous state.
prevX - newX / prevScale = prevXScaled / prevScale - newX / prevScale = (prevXScaled - newX) / prevScale
Add the new offset in the newly scaled coordinate system:
deltaTranslate + newTranslate = deltaTranslate + newX / newScale = (prevXScaled - newX) / prevScale + newX / newScale
Visual explanation
The principle of calculating transformations:
Original image:
Scaling:
Moving:
Calculation example:
X - Coordinates in the original system X' - Coordinates in the scaled system |
Implementation in Java
private AffineTransform prevTransform = new AffineTransform();
private void applyTransformation(Graphics2D g2d) {
final Point mousePosition = getMousePosition(); // method of Component class
if (null != mousePosition) {
final int x = mousePosition.x, y = mousePosition.y;
g2d.scale(zoom, zoom);
// Translate the current coordinates back to the previous coordinate system and perform the previous shift.
g2d.translate(
// translateX(Y) - это уже масштабированное значение X(Y): translateX = prevX * prevScaleX
(prevTransform.getTranslateX() - x) / prevTransform.getScaleX() + x / zoom,
(prevTransform.getTranslateY() - y) / prevTransform.getScaleY() + y / zoom);
if (isDragging) g2d.translate(dragX / zoom, dragY / zoom); // dragX - это dX, delta X, изменение координаты при перетаскивании
dragX = 0;
dragY = 0;
} else {
g2d.setTransform(prevTransform);
}
prevTransform = g2d.getTransform();
}
Sources could be downloaded from Github: https://github.com/asilichenko/mouse-move-scale
No comments:
Post a Comment