73.1.2 Transformations

A transformation is an algorithm that alters (or “transforms”) the size, orientation, and shape of objects which are copied from one coordinate space into another. Although a transformation affects the object as a whole, it is actually applied to each point, or to each line, that composes the object.

73.1.2.1 World- to Page-Space Transformations

The world- to page-space transformations are new to Windows. They add rotation, shear, and reflection capabilities which were not available in previous versions of the interface. The following sections describe these transformations, illustrate their effect, and provide the algorithms used to obtain those effects.

Translation

When translation occurs, each point in an object is shifted vertically and/or horizontally by a specified amount. The following illustration shows a 20-unit by 20-unit rectangle that was translated to the right by 10 units as it was copied from world coordinate-space to page coordinate-space:

Translation

In the previous illustration, the x-coordinate of each point in the rectangle is 10 units greater than the original x-coordinate.

Horizontal translation can be represented by the following algorithm:

x' = x + Dx

Where x' is the new x-coordinate, x is the original x-coordinate, and Dx is the horizontal distance moved.

And, vertical translation can be represented by the following algorithm:

y' = y + Dy

Where y' is the new y-coordinate, y is the original y-coordinate, and Dy is the vertical distance moved.

The horizontal and vertical translation transformations can be combined into a single operation using a 3-by-3 matrix:

|x' y' 1| = |x y 1| * |1 0 0|

|0 1 0|

|Dx Dy 1|

(The rules of matrix multiplication state that the number of rows in one matrix must equal the number of columns in the other—the integer value 1 which appears in the matrix |x y 1| is a placeholder that was added to meet this requirement.)

The three-by-three matrix that produced the illustrated transformation contained the following values:

|1 0 0|

|0 1 0|

|10 0 1|

Scaling

When scaling occurs, the vertical or horizontal lines (or vectors) which constitute an object are stretched or compressed with respect to the x- or the y-axis. The following illustration shows a 20-unit by 20-unit rectangle that was scaled vertically to twice it's original height as it was copied from the world coordinate-space to the page coordinate-space:

In the previous illustration, the vertical lines that define the original rectangle's side measure 20 units while the vertical lines that define the scaled rectangle's sides measure 40 units.

Vertical scaling can be represented by the following algorithm:

y' = y * Dy

Where y' is the new length, y is the original length, and Dy is the vertical scaling factor.

And, horizontal scaling can be represented by the following algorithm:

x' = x * Dx

Where x' is the new length, x is the original length, and Dx is the horizontal scaling factor.

The vertical and horizontal scaling transformations can be combined into a single operation using a 2-by-2 matrix:

|x' y'| = |Dx 0| * |x y|

|0 Dy|

The two-by-two matrix that produced the illustrated transformation contained the following values:

|1 0|

|0 2|

Rotation

When rotation occurs, the points that constitute an object are rotated with respect to the coordinate-space origin. The following illustration shows the same 20-unit by 20-unit rectangle used for previous illustrations after it was rotated 30 as it was copied from the world coordinate-space to the page coordinate-space:

In the previous illustration, each point in the rectangle is rotated 30 with respect to the coordinate-space origin.

The following algorithm computes the new x-coordinate (x') for a point (x,y) that is rotated by angle A with respect to the coordinate-space origin:

x' = (x * cos A) - (y * sin A)

The following algorithm computes the y-coordinate (y') for a point (x,y) that is rotated by the angle A with respect to the origin:

y' = (x * sin A) - (y * cos A)

The two rotation transformations can be combined in a two-by-two matrix as shown below:

|x' y'| == |x y| * | cos A sin A|

|-sin A cos A|

The two-by-two matrix that produced the illustrated rotation contained the following values:

| .8660 .5000|

|-.5000 .8660|

Since the rotation algorithms are less intuitive than the translation or scaling algorithms, the following explanation is provided.

The Rotation Algorithm Derivation

The rotation algorithms are based on trigonometry's addition theorem which states that the trigonometric function of a sum of two angles (A1 and A2) can be expressed in terms of the trigonometric functions of the two angles:

sin(A1 + A2) = (sin A1 * cos A2) + (cos A1 * sin A2)

cos(A1 + A2) = (cos A1 * cos A2) - (sin A1 * sin A2)

The following illustration shows a point p that has been rotated counterclockwise to a new position p' as well as the two triangles which are formed by the points, the coordinate-space origin, and the intersection of a line drawn through each point and perpendicular to the x-axis:

Rotation Derivation

From trigonometry, we know that the x-coordinate of point p can be obtained by multiplying the length of the hypotenuse h by the cosA1:

x = h * cos A1

And, we know that the y-coordinate of point p can be obtained by multiplying the length of the hypotenuse h by the sinA1:

y = h * sin A1

Likewise, we know that the x-coordinate of point p' can be obtained by multiplying the length of the hypotenuse h by the cos(A1 + A2):

x' = h * cos (A1 + A2)

And the y-coordinate of point p' can be obtained by multiplying the length of the hypotenuse h by the sin(A1 + A2):

y' = h * sin (A1 + A2)

Using the addition theorem, the previous algorithms become:

x' = (h * cos A1 * cos A2) - (h * sin A1 * sin A2)

y' = (h * cos A1 * sin A2) - (h * sin A1 * cos A2)

Substituting x for each occurrence of (h * cos A1) and substituting y for each occurrence of (h * sin A1), we obtain the rotation algorithms for a given point that is rotated by angle A2:

x' = (x * cos A2) - (y * sin A2)

y' = (x * sin A2) - (y * cos A2)

Shear

There are two components of the shear transformation: the first alters the vertical lines in an object while the second alters the horizontal lines. The following example shows a 20-unit by 20-unit rectangle that was sheared horizontally when it was copied from the world-space to the page-space:

Shear

Horizontal shear can be represented by the following algorithm:

x' = x + (Sx * y)

Where x is the original x-coordinate of the point p, Sx is the proportionality constant, and x' is the result of the shear transformation.

Vertical shear can be represented by the following algorithm:

y' = y + (Sy * x)

Where y is the original y-coordinate of the point p, Sy is the proportionality constant, and y' is the result of the shear transformation.

The horizontal- and vertical-shear transformations can be combined into a single operation using a two-by-two matrix:

|x' y'| == |x y| * | 1 Sx|

| Sy 1|

The two-by-two matrix that produced the illustrated rotation contained the following values:

|1 1|

|0 1|

Reflection

The reflection transformation creates a “mirror” image of an object with respect to either the x- or the y-axis. The following illustration shows a 20-unit by 20-unit rectangle that was reflected horizontally and then vertically when it was copied from the world coordinate-space into the page coordinate-space:

Reflection

Horizontal reflection can be represented by the following algorithm:

x' = x * Rx

Where x is the x-coordinate of the point p, Rx is negative one (-1), and x' is the result of the reflection.

Vertical reflection is represented by the following algorithm:

y' = y * Ry

Where y is the y-coordinate of the point p, Ry is negative one (-1), and y' is the result of the reflection.

The horizontal- and vertical-reflection operations can be combined into a single operation using a two-by-two matrix:

|x' y'| == |x y| * |Rx 0|

|0 Ry|

The two-by-two matrix that produced the illustrated reflection contained the following values:

|-1 0|

|0 1|

The Combined World-to-Page Transformations

You can combine the five world-to-page transformations into a single three-by-three matrix; and, you can use these combined transformations to alter output associated with a particular device context by calling the SetWorldTransform function and supplying the elements for this matrix. You can retrieve the elements of the current world-transform matrix by calling the GetWorldTransform function.

73.1.2.2 Page- to Device-Space Transformations

The page- to device-space transformation was part of the original Windows interface. (The page-space was referred to as the logical space in early versions of Windows.) This transformation determines the mapping mode for all graphics output associated with a particular device context. A mapping mode is a scaling transformation that specifies the size of the units used for drawing operations (in some cases the mapping mode alters the orientation of the x- and the y-axis in device space). There are five mapping modes; each is described in the following list:

Mapping Mode Description

MM_ANISOTROPIC Each unit in page space is mapped to an application-specified unit in device space. The axis may or may not be equally scaled (this means that a circle drawn in world-space may appear to be an ellipse when it is rendered on the device). The orientation of the axis is also specified by the application.
MM_HIENGLISH Each unit in page space is mapped to 0.001 inch in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_HIMETRIC Each unit in page space is mapped to 0.01 millimeter in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_ISOTROPIC Each unit in page space is mapped to an application-specified unit in device space. The axis are always equally scaled. The orientation of the axis may be specified by the application.
MM_LOENGLISH Each unit in page space is mapped to 0.01 inch in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_LOMETRIC Each unit in page space is mapped to 0.1 millimeter in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_TEXT Each unit in page space is mapped to one pixel. Increasing values of x occur as you move to the right; increasing values of y occur as you move down.
MM_TWIPS Each unit in page space is mapped to one twentieth of a printer's point (1/1440 inch). Increasing values of x occur as you move to the right; increasing values of y occur as you move down.

You set a mapping mode by calling the SetMapMode function. You retrieve the current mapping mode for a device context by calling the GetMapMode function.

Unlike the world- to page-space transformations which use a 3-by-3 matrix, the page- to device-space transformations use the width and the height ratios of two rectangles: the rectangle in page space is called a window and the rectangle in device space is called a viewport. The transformation occurs when Windows maps the window origin to the viewport origin and the window extents to the viewport extents. The following figure illustrates this mapping:

Page-Space to Device-Space Transformation

For the six predefined mapping modes (MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, MM_TEXT, MM_TWIPS), the width and height of these rectangles are set by Windows when you call SetMapMode—they cannot be changed. The other two mapping modes (anisotropic and isotropic), require that you specify the width and height of these rectangles. This is done by calling SetMapMode to set the appropriate mode and then by calling SetViewportExtEx and SetWindowExtEx to specify the width and height of each rectangle.

The Predefined Mapping Modes

Of the six predefined mapping modes, one is device-dependent (MM_TEXT) while the remaining five (MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, and MM_TWIPS) are device independent. The device-dependent mapping mode is provided for text-output operations that use device-specific fonts. Device-specific fonts are fonts are created for a device with a specific aspect ratio. The aspect ratio of a device is the ratio formed by the width and height of a single pixel. (You can retrieve a device's aspect ratio and the total number of device-specific fonts by calling the GetDeviceCaps function. You can limit the user's selection of fonts to device-specific only by calling the ChooseFont function and setting the CF_PRINTERFONTS or CF_SCREENFONTS constants.) The device-independent mapping modes are provided for non-text drawing operations: if your application displays geometric objects (circles, squares, polygons, and so on), you should choose one of the device independent mapping modes. For example, if you're writing code to provide charting capabilities for a spreadsheet application, and you want to guarantee that the diameter of each pie-chart is 2 inches, you could choose the MM_LOENGLISH mapping mode and call the appropriate functions to draw and fill the charts. By specifying loenglish as the mapping mode, you guarantee that the diameter of the charts will be consistent on any display or printer. (If you were to choose MM_TEXT instead of MM_LOENGLISH, a chart that appeared circular on a VGA display would appear elliptical on an EGA display and would appear incredibly small on a 300 dpi laser printer.)

The Developer-Defined Mapping Modes

The two developer-defined mapping modes (MM_ISOTROPIC and MM_ANISOTROPIC) are provided for application-specific mapping modes. The MM_ISOTROPIC mode guarantees that logical units in the x- and y-direction are equal while the MM_ANISOTROPIC mode allows the units to differ. A CAD or drawing application is an example of an application that could benefit from the MM_ISOTROPIC mapping mode: These applications may need to specify logical units that correspond to the increments on an engineer's scale (1/64 of an inch). These units would be difficult to obtain with the predefined mapping modes (MM_HIENGLISH or MM_HIMETRIC); however, they can easily be obtained by selecting the MM_ISOTROPIC mode, setting the window extents to the width and height of the display (expressed in 64ths of an inch) and setting the viewport width and height to the width and height of the display in pixels.

73.1.2.3 Device-Space to Physical-Device Transformation

The device-space to physical-device transformation is unique in several respects: it is limited to translation and it is controlled by the Window Manager component of Windows. The sole purpose of this transformation is to ensure that the origin of device space is mapped to the proper point on the physical device. There are no functions to set this transformation; nor are there any functions to retrieve related data.