Scale a rotated image with zoom center (Delphi, fmx)


I am trying to build a seemingly simple GUI in which a Timage can be panned, zoomed, and rotated. The zooming and rotating should be done at/around a defined zoom and rotation center position.
I am first trying this on Windows. All is working fine now, except that when the image has a rotation, the zoom at a specific zoom center does not work (the zoom center moves around). It does work fine when the rotationangle=0. I can indulge again in the math to get correct image position equations, but first wanted to ask here if someone has maybe tackled this problem before.
For the code below to work do the following:

start a new blank fmx multidevice project
Add a TPanel aligned to client
Add a TImage, fill its MultiResBitmap property with any image
Set the hittest property of the image to false (panel input used for zoom)

In the minimum code sample below the image is rotated in the form’s FormCreate procedure (or not to see how the zooming at a certain point is supposed to work). Zooming is done at the mouse position when scrolling the wheel on the mouse in the Panel1MouseWheel procedure.
So what would need to be adjusted are only the two lines below the comment
// correction for image position when scaling
procedure TForm1.FormCreate(Sender: TObject);
// Image1.RotationAngle := 0;
Image1.RotationAngle := 30;

procedure TForm1.Panel1MouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; var Handled: Boolean);
var zoom_center: TPointF;
new_scale,old_scale: single;
P1,P2: TPointF;
// Scaling (mousewheel)
if shift = [] then
zoom_center := screen.MousePos – ClienttoScreen(Image1.LocalToAbsolute(PointF(0,0)));

old_scale := Image1.Scale.X;
if WheelDelta>=0 then new_scale := old_scale * (1 + (WheelDelta / 120)/5)
else new_scale := old_scale / (1 – (WheelDelta / 120)/5);

Image1.Scale.X := new_scale;
Image1.Scale.Y := new_scale;

// correction for image position when scaling
Image1.Position.X := Image1.Position.X + zoom_center.x * (1-new_scale/old_scale);
Image1.Position.Y := Image1.Position.Y + zoom_center.y * (1-new_scale/old_scale);

Comments are closed.