RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Terrific Transformations : Page 4

Learn how to use .NET transformations to make rotating, stretching, and moving objects simple--even for complex objects such as paths and text.

Inverting Transformations
When you need to fit a picture to a printed page, the transformation functions described in the previous section are just about all you need. You create the proper transformation, draw on the paper, and you're done.

When you transform a drawing on the screen, however, you sometimes need to reverse the transformation. For example, suppose you want to let the user interact with a bar chart or map that you've drawn on the screen. If you use transformations to scale the image to fit the form, then the point where the user clicks doesn't necessarily match up with the original drawing coordinates. In other words, the user's click is in device coordinates but the image data is in world coordinates.

To draw the picture, you build a transformation that maps from world coordinates to device coordinates. To see where the user clicked, you need a transformation that maps back from device coordinates to world coordinates. Fortunately each of the transformations used in this article have simple inverses: the inverse of a translation by (td, ty) is a translation by (-tx, -ty); the inverse of a scaling by (sx, sy) is a scaling by (1/sx, 1/sy); and the inverse of a rotation by theta degrees is a rotation by —theta degrees.

Figure 7. Translating from Device Coordinates to World Coordinates: The example program 'BullsEye" maps user mouse clicks from device coordinates to world coordinates.
To invert a series of transformations, you just apply the inverse transformations in reverse order. For example, the inverse of TranslateTransform(10, 20), ScaleTransform(-2, 4), RotateTransform(30) is RotateTransform(-30), ScaleTransform(-1/2, 1/4), TranslateTransform(-10, -20).

While you could build this transformation yourself easily enough, the Matrix class provides an Invert method that makes the process even easier. Simply create a Matrix object that represents the Graphics object's transformation and call its Invert method. Then you can use the inverted Matrix's TransformPoints method to map points back from device coordinates to world coordinates.

The example program BullsEye, shown in Figure 7, uses transformations to draw the same bull's-eye in three differently shaped PictureBoxes. When the user clicks on a picture, the program uses an inverted transformation to find the point that the user clicked in world coordinates. It then tells the user which region was clicked in the form's caption.

When BullsEye starts, it builds the transformations it will need later to map the bull's-eye drawing onto the PictureBoxes. It also inverts those transformations and saves the results so it can map user clicks to world coordinates.

The following code shows how the program builds the transformations for the first PictureBox. The code for the other PictureBoxes is similar so I've omitted it to save space:

   Private m_WtoD1 As Matrix ' World to device
   Private m_DtoW1 As Matrix ' Device to world
   ' Make transforms.
   Private Sub Form1_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
       Dim world_rect As New RectangleF(-1, -1, 2, 2)
       Dim device_rect As RectangleF
       ' PictureBox1.
       device_rect = PictureBox1.ClientRectangle
       device_rect.Width -= 1
       device_rect.Height -= 1
       m_WtoD1 = StretchToFitWorld(world_rect, device_rect)
       m_DtoW1 = m_WtoD1.Clone
   End Sub
This code builds rectangles to represent the world and device coordinates (it subtracts a bit from the PictureBox's client rectangle so the picture doesn't get covered by the control's border at the edges) and calls the StretchToFitWorld method to make a transformation that stretches the world coordinates to fit the PictureBox.

The code then uses the transformation matrix's Clone method to make a copy of the matrix and calls the copy's Invert method to make the inverse transformation.

The following code shows how the program responds to mouse clicks on PictureBox1:

   Private Sub PictureBox1_MouseClick(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles PictureBox1.MouseClick
       ' Draw the point.
       Using gr As Graphics = PictureBox1.CreateGraphics()
           gr.FillEllipse(Brushes.Blue, e.X - 2, e.Y - 2, 5, 5)
       End Using
       ' Get the point in device coordinates.
       Dim ptf() As PointF = {New PointF(e.X, e.Y)}
       ' Translate into world coordinates.
       ' See where the user clicked.
       Dim dist As Single = ptf(0).X * ptf(0).X + ptf(0).Y * ptf(0).Y
       Select Case dist
           Case Is < 0.25 * 0.25
               Me.Text = "Bulls eye!"
           Case Is < 0.5 * 0.5
               Me.Text = "50 points"
           Case Is < 0.75 * 0.75
               Me.Text = "20 points"
           Case Is < 1 * 1
               Me.Text = "10 points"
           Case Else
               Me.Text = "Miss"
       End Select
   End Sub
The code starts by marking the point that the user clicked. It then makes an array of PointF objects containing that point. It uses the inverse transformation matrix m_DtoW1 to transform the point from device coordinates back into world coordinates. Finally the code checks the point's distance from the origin to see how far the point is from the bull's-eye in world coordinates and displays an appropriate message in the form's title bar.

Transformations let you change the way the Graphics object's drawing methods work, translating, scaling, and rotating the results without changing the drawing code. That lets you make adjustments and reuse code by executing the same drawing code with different transformations. It lets you easily center a picture, possibly while enlarging it with or without stretching.

Most importantly, transformations let you draw in world coordinates that make sense for your application without worrying about how the final result will be mapped onto the device coordinates used by the screen. Inverse transformations let you translate device coordinates back into world coordinates if you need to let users interact with the drawing.

Taken together, these techniques add an entirely new element to your graphics programming that simple Pens and Brushes don't provide on their own.

Rod Stephens is a consultant and author who has written more than a dozen books and two hundred magazine articles, mostly about Visual Basic. During his career he has worked on an eclectic assortment of applications for repair dispatch, fuel tax tracking, professional football training, wastewater treatment, geographic mapping, and ticket sales. His VB Helper web site receives more than 7 million hits per month and provides three newsletters and thousands of tips, tricks, and examples for Visual Basic programmers.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date