Using Transforms in your PM Graphics Applications

by Kelvin R. Lawrence The OS/2 Graphical Programming Interface (GPI) contains many powerful features that let you construct and manipulate graphical shapes. However, many programmers have avoided using these features in their applications. There is a myth, it seems, that the GPI is hard to program to and hard to learn. In reality, this is not the case. This article shows you how the GPI lets you work with its transformation matrices and describes how to setup simple transformations to change the way picture components or whole pictures are drawn.

This article; however, describes some of the effects you can achieve by using just the model transform.

The Model Transform
The model transform is a general purpose work-horse transformation that lets you adjust the way a shape is drawn in a number of ways. One or more of the following effects can be achieved:
 * Translation: Move the shape to a new position
 * Rotation: Rotate the shape by a number of degrees
 * Scaling: Make the shape bigger or smaller
 * Reflection: Draw the mirror image of a shape
 * Shearing: Add a shear to the shape



''Figure 1. Different Effects Using the Model Transform''

Manipulate each transform by creating and modifying a MATRIXLF structure as defined in the PMGPI.H header file in The Developer's Toolkit for OS/2 2.1.

The MATRIXLF structure is defined in C as: In more traditional matrix notation, think of the MATRIXLF structure as a three by three matrix as follows:



To get the new value of a point about to be drawn, multiply the (x,y) coordinate against a transform matrix as follows:



As shown in Figure 1, you can combine the different elements of the transformation matrix (MATRIXLF) structure in various ways to achieve various effects:

If you are working with a presentation space created so that the page units are defined as pels, then, by default, the GPI initializes the model transform to identity. In other words, it has no effect on anything. If you multiply an (x,y) coordinate against the transform it remains unchanged. However, if you are working in page units other than pels, the graphics subsystem initializes the model transform to match the page units that the application uses. Given that the GPI uses the lM31 and lM32 elements of the transformation matrix structure for translating points, the following example illustrates the previous points.

Assuming we are working in pels and that we have not yet adjusted the model transform then it will be initialized as an identity matrix as follows:



Assuming we wanted a translation of 100 pels in both the x and y directions to be applied to all subsequent drawing operations, we can set up the lM31 and lM32 elements to reflect this as follows:



So, with our transform set up to do the translation, assume that you have a coordinate (20,20). Multiplying this coordinate against our transformation matrix, using standard matrix mathematics, the resultant coordinate reflects the translation having taken effect, as follows:



This multiplication process could also be written as: x' = ( fxM11*x + fxM21*y + lM31 ) y' = ( fxM12*x + fxM22*y + lM32 )

Translating and Sizing a Box
To translate and scale a box, first define a function DrawBox that draws a box in the bottom left-hand corner of the window. This function simply draws a box10 pels by 10 pels starting at coordinate (0,0), of the presentation space associated with the window whose handle is passed in on the call. ''Sample Program 1. Drawing a Box''

Next, modify the function to draw the same 10 by 10 box, but first set up a model transform that will offset the box 100 pels in both the x and y directions and will cause the box to be scaled up (enlarged) by a factor of 10 in both the x and y directions. We will call this modified function DrawTransformedBox. Query the current settings of the model transform using the GpiQueryModelTransformMatrix function and set its new value using the GpiSetModelTransformMatrix function. Also, we still set the current position to (0,0) before we draw the box, and we still only draw a 10 by 10 box. All of the work to move the box and scale it is done because the transformation matrix was multiplied in before the points were actually drawn. ''Sample Program 2. Translating and Scaling a Box''

This very simple example shows how, in very few lines of code, you can define a transform and dramatically change the appearance of the output.

Helper Functions
While it is important to understand the fundamental mechanics of the transformation matrices and the meanings of their individual elements, the GPI provides a set of helper functions to do the work of manipulating and setting up the matrices for various operations. These helper functions are:
 * GpiTranslate Used to set up coordinate translations
 * GpiScale Used to set up a scaling transform
 * GpiRotate Used to set up a transform to do rotation

Rotating a Box
The function RotateBox lets you use the model transform with the GpiRotate function to draw a series of boxes rotated through 360 degrees in 10 degree intervals. ''Sample Program 3. Rotating a Box''

Summary
This article concentrated on just one of the transforms and explored a few of the ways it can be used. Look for future articles on the other transformations in The Developer Connection News.

The only real way to discover the full power of the GPI transformation matrices is to try using them in your applications. I urge all of you that are interested in getting the most out of the GPI to do just that; experiment for yourselves. Indeed, we would love to publish any great samples you might come up with on future releases of The Developer Connection for OS/2 CD-ROM.

About the Author - Kelvin Lawrence
Kelvin R. Lawrence is an architect working on the design of IBM's Workplace OS Graphical Subsystem. He was the Lead Programmer for the development of the OS/2 2.1 Presentation Manager. Kelvin has been a key member of OS/2 development and support since 1986.