Programming Guide:xppguide

Graphic transformations and raster operations Foundation

The GRA engine allows drawings created with graphic primitives to be transformed. "Transformed" means that a drawing can be turned, inverted, enlarged or reduced in size. There is an important distinction here between vector and raster images. A vector image is a drawing defined only by points in the coordinate system and how these points are connected with each other by lines. The lines can define the border for an area and the area can be filled with a color or a pattern. A raster image, however, is just an area filled with dots of color. The area is divided up by a raster and each dot in the raster has its own color. A raster image is generally called a "bitmap". A dot in a bitmap is called a "pixel".

There are three functions in the GRA engine for transforming vector images and a single function for performing raster operations. These four functions are listed in the following table:

Functions for transformations and raster operations
Function Description
GraRotate() Calculates rotation transformation matrix
GraScale() Calculates scaling transformation matrix
GraTranslate() Calculates translation transformation matrix
GraBitBlt() Performs operations with raster images (bitmaps)

Transformation from vector images

The six graphic primitives of the GRA engine are used to create vector images (except that when a bitmap font is set, character strings are drawn as raster images). A vector image can be transformed in any manner. There is the practical limitation that transformation of graphic primitives is not possible, but only the transformation of graphic segments (these contain graphic primitives). Thus, when drawings are to be transformed they must be defined within graphic segments.

The three possible graphical transformations of a vector image involve the operations of "rotating" (turn an image), "scaling" (enlarge or reduce an image) and "translating" (move, copy or invert an image). Each of these operations requires that a transformation matrix be calculated. The calculations for the three possible transformations are done using the functions GraRotate(), GraScale() and GraTranslate(). The three functions only calculate a transformation matrix for one of these three possible graphical transformations, they do not display anything. The transformation matrix itself is a two dimensional array with three rows and three columns. The array must be created before the transformation using GraInitMatrix(). GraInitMatrix() is a pseudo function defined in GRA.CH. It is translated into a two dimensional array which must be used for calculating a transformation matrix.

To make the transformation visible, the graphic segment must be redrawn. This occurs using the function GraSegDraw() and passing the transformation matrix containing the result of the calculations for the desired transformation to this function. Here is an example:

#include "Gra.ch" 

PROCEDURE Main 
   LOCAL  nSegment, i, aMatrix := GraInitMatrix() 

   SetColor("N/W")                   // fill window with pale gray 
   CLS 

   nSegment := GraSegOpen()          // define segment 
      GraBox( NIL, {200,150}, {300,230}, GRA_OUTLINE ) 
   GraSegClose()                     // create a box in a segment 

   GraSegDraw( NIL, nSegment )       // display box 

   FOR i:=1 TO 12                    // draw box 12 times rotating 
                                     // each one 30 degrees left 
      GraRotate ( NIL, aMatrix, -30, {200,150}, GRA_TRANSFORM_ADD ) 
      GraSegDraw( NIL, nSegment, aMatrix ) 
   NEXT 
RETURN 

In this example, a graphic segment is created that contains only one graphic primitive (GraBox()). Within the FOR..NEXT loop, the segment is drawn 12 times and each time a rotation of -30 degrees is calculated based on a turning point at the lower left corner of the box (the point {200,150}). The negative angle -30 degrees causes a rotation to the left (a positive angle would cause a rotation to the right). The example shows that it is essential to first calculate the transformation matrix. To calculate the transformation matrix, a matrix created by GraInitMatrix() is needed. The result of the calculation of GraRotate() is visible only after GraSegDraw() is called. The transformation matrix must be passed to the function GraSegDraw().

A graphic transformation requires a total of four steps. First, the transformation matrix must be created using GraInitMatrix(). The second step is defining the graphic segment containing the drawing to be transformed. Third, the transformation is calculated using GraRotate(), GraScale() or GraTranslate() to create the transformation matrix. Finally, the graphic transformation is displayed using GraSegDraw(). The transformation matrix previously calculated using GraRotate(), GraScale() or GraTranslate() must be passed to the function GraSegDraw().

The two #define constants GRA_TRANSFORM_ADD and GRA_TRANSFORM_REPLACE affect the calculation of repeated transformations. If GRA_TRANSFORM_ADD is specified the transformation matrix is left unchanged after it is used to display the segment. GRA_TRANSFORM_REPLACE (default) causes the transformation matrix to be reset to the initial value of GraInitMatrix() when the display using the matrix calculation is complete. Using GRA_TRANSFORM_ADD, several transformations can effectively be added together. GRA_TRANSFORM_REPLACE begins each graphic transformation with the initial matrix predetermined by GraInitMatrix().

These transformations are valid only for vector images. They cannot be applied to raster images (bitmaps).

Transformation of bitmaps - Raster operations

Raster images (bitmaps) can be transformed in a manner similar to vector images, with the limitation that images in the form of a bitmap cannot be turned (rotation is not possible with bitmaps). Bitmaps can be copied, enlarged or reduced in their entirety or in sections. The function GraBitBlt() handles these tasks. No transformation matrix needs to be calculated for transformations of raster images. The source and the target coordinates are passed to the function GraBitBlt() in the form of an array. GraBitBlt() processes the coordinates for the area of the bitmap which is to be copied and the coordinates for the area into which it is to be copied. The source coordinates correspond to the presentation space in which the raster image is already displayed and the target coordinates correspond to the presentation space into which it is copied. Both presentation spaces can be associated with the same device context. In this case, a raster image from the area of the source coordinates is copied to the area of the target coordinates. When the source and target coordinates describe areas of different sizes, automatic scaling of the raster image occurs. The following illustration shows the result of various raster operations using GraBitBlt(). The initial image is displayed upper left:

Raster operations with GraBitBlt()

To create this illustration, a bitmap is initially displayed in the upper left of the image and then the function GraBitBlt() is called four times using different source and target coordinates. The raster image is copied, enlarged, and reduced as a whole and in sections.

A special characteristic of the function GraBitBlt() is that the source and target areas of the raster operation can occur in two different presentation spaces. The output of the raster image depends on the device context linked to the presentation space when the display occurs. For example, it is possible to copy a raster image from a presentation space associated with a window to a presentation space associated with a printer device context. In this way raster images visible in a window can be output to a printer.

Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.