3 Simple use of TRANSFORM Routines

 3.1 Formulating a Transformation
 3.2 Creating a Transformation
 3.3 Temporary Transformations
 3.4 Compilation
 3.5 Inquiry Routines
 3.6 Transforming 1-Dimensional Coordinate Data
 3.7 Transforming 2-Dimensional Coordinate Data
 3.8 Clearing Up and Closing Down

3.1 Formulating a Transformation

The first stage in creating a transformation is to formulate a description of it in a form which may be used in a program. In future, there may be a number of ways of formulating such a description and of creating a corresponding transformation from it. At present, however, only one method is supported, based on the explicit use of transformation functions.

For instance, suppose you wished to create the [(x, y) (r, θ)] transformation relating a two-dimensional Cartesian coordinate system (x, y) to a Polar system (r, θ). In this case, the transformation’s two mappings might be defined in terms of the following transformation functions:

Forward  r =x2 + y2 θ = tan 1 y/x Inverse  x =r cos(θ) y =r sin(θ) (3)

This description of the transformation could now be used in a program by converting it directly into character data, as follows:

Example 2. Formulating a Cartesian-to-Polar transformation.
  *  Define the number of input and output variables.
        INTEGER NVIN, NVOUT
        PARAMETER ( NVIN = 2, NVOUT = 2 )
  
  *  Declare arrays for the forward and inverse transformation functions.
        CHARACTER * 25  FOR( NVOUT ), INV( NVIN )        [1]
  
  *  Assign the forward transformation functions.
        FOR( 1 ) = ’r = sqrt( x * x + y * y )’           [2][3]
        FOR( 2 ) = ’theta = atan2( y, x )’
  
  *  Assign the inverse transformation functions.
        INV( 1 ) = ’x = r * cos( theta )’
        INV( 2 ) = ’y = r * sin( theta )’
  

Programming notes:

(1)
The transformation functions are assigned to the elements of two character arrays FOR and INV, the number of elements in each array being determined by the number of output and input variables, NVOUT and NVIN respectively.
(2)
The formulae of Equation 3 have been converted into character data for storage in these arrays by using Fortran arithmetic operators and intrinsic functions (see Appendix A for a full description of the syntax of transformation functions, which closely resembles that of Fortran 77 assignment statements).
(3)
The names ‘x’, ‘y’, ‘r’ and ‘theta’ have been used to represent the transformation’s input and output variables. Names such as these may be chosen freely (see Appendix A) and are defined implicitly when they appear on the left hand side of a transformation function.

Unspecified mappings.  In the above example, both the forward and inverse mappings were defined. If only one of these were required, however, then the other could be left unspecified. This is done simply by omitting the right hand sides (and ‘ =’ signs) from the transformation functions which define it. Thus, if the inverse transformation functions had been specified as:
  INV( 1 ) = ’x’
  INV( 2 ) = ’y’
then the inverse mapping would not be defined. Note that the left hand sides of the transformation functions must still appear, however, because they define the names of the transformation’s input variables.

3.2 Creating a Transformation

The transformation functions formulated above may be used to create an HDS transformation structure by calling the routine TRN_NEW (create new transformation), as follows:

  CALL TRN_NEW( NVIN, NVOUT, FOR, INV, PREC, COMM, ELOC, NAME, LOCTR, STATUS )

where:

Example 3. Creating a Cartesian-to-Polar transformation.

The following arrangement might be used to create a transformation called MYTRAN from the FOR and INV arrays defined earlier:

  *  Declare variables.
        INCLUDE ’SAE_PAR’
        INCLUDE ’TRN_PAR’                                    [1]
        CHARACTER PREC * ( TRN__SZPRC ), COMM * 80
        CHARACTER * ( DAT__SZLOC ) ELOC, LOCTR
  
  *  Get a locator ELOC to an existing HDS structure.
        <a call to DAT_ASSOC or DAT_FIND, for instance>
  
  *  Specify the arithmetic precision and make a comment.
        PREC = ’_REAL:’                                      [2]
        COMM = ’2-d Cartesian (x,y) --> 2-d Polar (r,theta)  [3]
  
  *  Create the transformation.
        CALL TRN_NEW( NVIN, NVOUT, FOR, INV, PREC, COMM,     [4][5]
       :              ELOC, ’MYTRAN’, LOCTR, STATUS )
  

Programming notes:

(1)
The symbolic constant TRN__SZPRC is defined in the include file TRN_PAR. It is used to declare the length of the character variable PREC which will contain a precision specification.
(2)
PREC specifies the type of arithmetic to be used when the transformation functions are evaluated and has been assigned the value ‘_REAL:’, which is recommended for general use. This indicates that single precision (real) arithmetic should normally be used but that the precision may be increased if double precision data are being processed. This is discussed further in Section 5.2.
(3)
The ‘-->’ (or ‘<--’) character sequence may be used in comment strings to indicate the direction of the forward mapping. If the transformation is subsequently inverted (Section 4.5), then the ‘-->’ and ‘<--’ symbols will be interchanged so that the comment remains valid. Comments may be of any length.
(4)
TRN_NEW will check the transformation functions for correct syntax and consistent use of variable names before the transformation is created. However, no check is performed to determine whether the forward and inverse transformation functions actually define a pair of complementary mappings. It is the caller’s responsibility to ensure that this is so.
(5)
On successful exit from TRN_NEW, the LOCTR argument returns an HDS locator associated with the newly created transformation.

3.3 Temporary Transformations

The TRN_NEW routine may also be used to create a temporary transformation. This can be very convenient for internal use by an application because it avoids the need for an existing HDS structure to contain it. To create such a transformation, the ELOC argument to TRN_NEW should be replaced by a blank string (the NAME argument will then be ignored and may also be blank). Thus, if TRN_NEW were invoked by:

  CALL TRN_NEW( NVIN, NVOUT, FOR, INV, PREC, COMM, ’ ’, ’ ’, LOCTR, STATUS )

then the locator LOCTR would subsequently be associated with a temporary transformation (i.e. a temporary HDS structure of type TRN_TRANSFORM).

3.4 Compilation

The transformation structures created by TRN_NEW hold information in a form which can be easily manipulated by HDS. However, this form of storage is not efficient if the transformation is to be used, perhaps repeatedly, to process large arrays of data. Therefore, before a transformation can be used to transform coordinate data, its mapping information must first be compiled using TRN_COMP (compile transformation), thus:

        CALL TRN_COMP( LOCTR, FORWD, ID, STATUS )

The TRN_COMP routine accepts a locator LOCTR associated with a transformation and checks the information within it. It then compiles one of the transformation’s mappings into a different form which is stored internally by the TRANSFORM facility. This internal representation is called a compiled mapping and may subsequently be used (for instance) to convert coordinate data from one coordinate system to another. The logical argument FORWD is used to specify which mapping is required – the forward mapping is compiled if this argument is .TRUE. and the inverse mapping is compiled if it is .FALSE.. An error will be reported if the requested mapping has not been defined.

Any number of transformations may be compiled by repeatedly calling TRN_COMP. To distinguish the resulting compiled mappings, a unique integer identifier is issued for each via the ID argument, and these identifiers are subsequently used to pass the mappings to other routines.

It is important to appreciate that a compiled mapping is a “uni-directional” object and can only perform coordinate conversion in a single direction, whereas a transformation (which may contain up to two mappings) is potentially “bi-directional”. Thus, if an [m n] transformation is compiled in the forward direction (with the FORWD argument of TRN_COMP set to .TRUE.), then a {m n} mapping will result. Conversely, compilation in the inverse direction would yield a {n m} mapping. Note that in this latter case the numbers of input and output variables will have been interchanged by the compilation process.

3.5 Inquiry Routines

An application may determine the number of input and output variables used by a transformation by calling TRN_GTNV (get numbers of variables), thus:

  CALL TRN_GTNV( LOCTR, NVIN, NVOUT, STATUS )

The information is returned via the NVIN and NVOUT arguments. Since TRN_GTNV first checks that the locator LOCTR is associated with a valid transformation, this also provides a convenient way of validating a transformation.

A similar routine TRN_GTNVC (get numbers of compiled variables) is provided for use with compiled mappings:

  CALL TRN_GTNVC( ID, NVIN, NVOUT, STATUS )

In this case, the mapping is specified by its integer identifier ID.

3.6 Transforming 1-Dimensional Coordinate Data

A number of routines are provided for applying compiled mappings to arrays of coordinate data (i.e. lists of coordinates). They are distinguished according to the number of variables used by the mapping, by the way the data are stored in the arrays and by the type (i.e. numerical precision) of the data being transformed. The common and relatively simple cases of 1- and 2-dimensional data are discussed here and in the following Section. Section 4.1 describes the use of more general mappings.

The simplest situation arises when the input and output data points are both 1-dimensional, so that a {1 1} mapping is to be applied. Routines with names of the form TRN_TR1x are provided for this purpose, where x is either I, R or D according to whether the data are specified by integer, real or double precision values respectively. Thus, to apply a compiled {1 1} mapping to a set of 1-dimensional data points specified by a list of real coordinates, the following statement might be used:

  CALL TRN_TR1R( BAD, NX, XIN, ID, XOUT, STATUS )

where:

Example 4. Plotting a graph of a user-specified function.

In the following, TRN_TR1R is used to generate data for a graph. The function to be plotted is specified by the user via an expression obtained through the ADAM parameter system. For instance, if the user entered:

  X*EXP(-4.4*X)

then a graph of the function y = xe4.4x would be plotted over the range 0 x 1.

  *  Declare variables.
        INCLUDE ’SAE_PAR’
        INTEGER NPTS
        PARAMETER ( NPTS = 1000 )
        INTEGER STATUS, ID, IPOINT
        REAL X( NPTS ), Y( NPTS )
        CHARACTER EXPRS * 80, FOR( 1 ) * 82, INV( 1 ) * 1
        CHARACTER * ( DAT__SZLOC ) LOCTR
  
  *  Obtain an expression and formulate the transformation functions.
        CALL PAR_GET0C( ’EXPRESSION’, EXPRS, STATUS )           [1]
        FOR( 1 ) = ’Y=’ // EXPRS
        INV( 1 ) = ’X’
  
  *  Create a temporary transformation and compile it.
        CALL TRN_NEW( 1, 1, FOR, INV, ’_REAL:’,                 [2]
                      ’X --> f( X )’, ’ ’, ’ ’, LOCTR, STATUS )
        CALL TRN_COMP( LOCTR, .TRUE., ID, STATUS )
  
  *  Set up the X values, then transform to yield the Y values.
        DO 1 IPOINT = 1, NPTS
           X( IPOINT ) = REAL( IPOINT - 1 ) / REAL( NPTS - 1 )
      1 CONTINUE
        CALL TRN_TR1R( .FALSE., NPTS, X, ID, Y, STATUS )        [3]
  
  *  Plot the graph and clean up.
        CALL GPL( NPTS, X, Y )                                  [4]
        CALL DAT_ANNUL( LOCTR, STATUS )                         [5]
        CALL TRN_ANNUL( ID, STATUS )

Programming notes:

(1)
An expression is obtained via the parameter system and used to formulate suitable transformation functions. Only the forward mapping is specified.
(2)
A temporary transformation is created (TRN_NEW) and is then compiled (TRN_COMP).
(3)
After generating the X values, TRN_TR1R is called to apply the compiled mapping, thereby generating the corresponding Y values. The BAD argument is set to .FALSE. since there are no bad input coordinates.
(4)
A graph is plotted using the GKS polyline routine GPL. It is assumed that a suitable coordinate system has been established.
(5)
Lastly, a clean up is performed by annulling the temporary transformation (DAT_ANNUL) and the compiled mapping (TRN_ANNUL – described later in Section 3.8).

3.7 Transforming 2-Dimensional Coordinate Data

Transformations which inter-relate 2-dimensional coordinate systems are common in graphical and image-processing applications, so a set of routines is provided for applying the associated {2 2} mappings to coordinate data. These routines have names of the form TRN_TR2x, where x is either I, R or D according to whether the data are specified by integer, real or double precision values respectively. Thus, to apply a compiled {2 2} mapping to a set of 2-dimensional data points specified by two lists of real coordinates XIN and YIN, the following statement might be used:

  CALL TRN_TR2R( BAD, NXY, XIN, YIN, ID, XOUT, YOUT, STATUS )

where:

Example 5. Transforming a cursor position.

The following shows TRN_TR2R being used to transform 2-dimensional coordinate data obtained by reading a cursor. It is assumed that the identifier ID is associated with a compiled {2 2} mapping which has been established to convert cursor coordinates into “user” coordinates:

  *  Declare variables.
        INTEGER STATUS, N, ID
        REAL XCUR( 1 ), YCUR( 1 ), XUSER( 1 ), YUSER( 1 )
  
  *  Set up cursor choice device.
        CALL SGS_SELCH( 0 )
        CALL SGS_DEFCH( ’.’ )
  
  *  Loop to read cursor positions.
        DO WHILE ( STATUS .EQ. SAI__OK )
           CALL SGS_REQCU( XCUR( 1 ), YCUR( 1 ), N )      [1]
           IF( N .NE. 0 ) GO TO 1
  
  *  Transform the cursor coordinates.
           CALL TRN_TR2R( .FALSE., 1, XCUR, YCUR, ID,     [2]
       :                  XUSER, YUSER, STATUS )
  
  *  Display the position in user coordinates.
           CALL MSG_SETR( ’X’, XUSER( 1 ) )
           CALL MSG_SETR( ’Y’, YUSER( 1 ) )
           CALL MSG_OUT( ’ ’, ’X = ^X ; Y = ^Y’, STATUS ) [3]
        ENDDO
      1 CONTINUE

Programming notes:

(1)
The SGS cursor position is read repeatedly until the user terminates interaction (by pressing the keyboard ‘.’ key in this case).
(2)
TRN_TR2R is used to transform each cursor position in turn into “user” coordinates. Only a single data point is transformed here, but in a non-interactive application it would be more efficient to transform a whole set of data points in a single call to this routine.
(3)
The transformed positions are displayed in “user” coordinates.

3.8 Clearing Up and Closing Down

When a compiled mapping is no longer required, the resources associated with it should be released. This is done by calling TRN_ANNUL (annul compiled mapping), thus:

  CALL TRN_ANNUL( ID, STATUS )

This causes the compiled mapping to be deleted and the ID value to be reset to TRN__NOID.3 Finally, before an application finishes, the statement:

  CALL TRN_CLOSE( STATUS )

should be executed. Calling TRN_CLOSE will first annul any compiled mappings which are still active and will then close the TRANSFORM facility down, recovering any resources associated with it.

Both of these cleaning up routines will attempt to execute regardless of the value of their STATUS argument.

3The symbolic constant TRN__NOID is defined in the include file TRN_PAR. It is provided as a “null” value, which is guaranteed never to be used as a compiled mapping identifier. It may be used, when necessary, to indicate that an identifier is not currently associated with a compiled mapping.