Title: Let the user zoom on a picture and draw in C#
The example Let the user zoom on a picture in C# allows the user to zoom in on a picture and draw on it. Unfortunately, it doesn't handle the drawing properly when the image is scaled. It doesn't scale the mouse's position properly when the image is scaled.
This example corrects that. The idea is to create a Matrix object that represents the inverse of the scaling transformation. Then when the user draws, the program uses the transformation to convert the mouse's position into the scaled drawing coordinate system so the points can be saved appropriately.
The following code shows how the program declares its transformation matrix.
// Inverse transform to convert mouse coordinates.
private Matrix InverseTransform = new Matrix();
The Matrix class is defined in the System.Drawing.Drawing2D namespace, so the program includes a using System.Drawing.Drawing2D directive to make using the class easier.
When you select a scale, the program calls the following method to prepare to use the new scale. The new code is highlighted in blue.
// Set the scale and redraw.
private void SetScale(float picture_scale)
{
// Set the scale.
PictureScale = picture_scale;
// Resize the PictureBox.
picCanvas.ClientSize = new Size(
(int)(WorldWidth * PictureScale),
(int)(WorldHeight * PictureScale));
// Prepare the inverse transformation for points.
InverseTransform = new Matrix();
InverseTransform.Scale(1.0f / picture_scale, 1.0f / picture_scale);
// Redraw.
picCanvas.Refresh();
}
The highlighted code sets InverseTransform to a new Matrix object. It then calls the object's Scale method to make the matrix represent scaling by the inverse of the current scale factor.
For example, suppose the scale factor is 2. Then the inverse scale factor is 1/2. When the user moves the mouse across the scaled image, the logical location of the mouse in drawing coordinates is twice what it is on the screen because the image is enlarged. When you move the mouse 10 pixels across the screen, you are moving across 20 pixels worth of drawing.
The following code shows the only other pieces of the program that use the inverse transform matrix. Again the changes are highlighted in blue.
// Start drawing.
private void picCanvas_MouseDown(object sender, MouseEventArgs e)
{
// Create the new polyline.
NewPolyline = new Polyline();
Polylines.Add(NewPolyline);
// Initialize it and add the first point.
NewPolyline.Color = DrawingColor;
NewPolyline.Thickness = DrawingThickness;
NewPolyline.DashStyle = DrawingDashStyle;
// Transform the point for the current scale.
Point[] points = { e.Location };
InverseTransform.TransformPoints(points);
NewPolyline.Points.Add(points[0]);
}
// Continue drawing.
private void picCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (NewPolyline == null) return;
// Transform the point for the current scale.
Point[] points = { e.Location };
InverseTransform.TransformPoints(points);
NewPolyline.Points.Add(points[0]);
picCanvas.Refresh();
}
The code is similar to the previous version, except this time the program scales the mouse's position before adding it to the NewPolyline object's points. To scale the point's coordinates, the code copies the point into an array and then calls the InverseTransform object's TransformPoints method to apply the transformation to the array.
The rest of the program is the same as before. Now that the new point is scaled to match the image's scale factor, the original drawing methods still work.
Download the example to experiment with it and to see additional details.
|