3 Simple use of TRANSFORM Routines
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
[]
transformation relating a two-dimensional Cartesian coordinate system
to a Polar
system . In
this case, the transformation’s two mappings might be defined in terms of the following
transformation functions:
| (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:
- NVIN and NVOUT are the numbers of input and output variables;
- FOR and INV are the two character arrays containing the forward and inverse
transformation functions;
- PREC is a character expression specifying the arithmetic precision with which the
transformation functions will be evaluated;
- COMM is a comment to be stored with the transformation;
- ELOC is a locator to an existing HDS structure;
- NAME is the HDS name of the new structure component to be created;
- LOCTR returns a locator to the newly created transformation structure;
- STATUS is an inherited error status variable.
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
[]
transformation is compiled in the forward direction (with the FORWD argument of TRN_COMP set to .TRUE.),
then a {}
mapping will result. Conversely, compilation in the inverse direction would yield a
{}
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
{}
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
{}
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:
- BAD is a logical value specifying whether the input coordinates may contain bad values
(see Section 4.2);
- NX specifies the number of data points to be transformed;
- XIN is a 1-dimensional array containing the coordinates of the input data points;
- ID is an identifier associated with the compiled {}
mapping to be applied;
- XOUT is a 1-dimensional array to receive the (transformed) coordinates of the output
data points;
- STATUS is an inherited error status variable.
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:
then a graph of the function
would be plotted over the range .
* 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
{} 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 {}
mapping to a set of 2-dimensional data points specified by two lists of real coordinates
and
, the
following statement might be used:
CALL TRN_TR2R( BAD, NXY, XIN, YIN, ID, XOUT, YOUT, STATUS )
where:
- BAD is a logical value specifying whether the input coordinates may contain bad values
(see Section 4.2);
- NXY specifies the number of data points to be transformed;
- XIN and YIN are 1-dimensional arrays containing the
and
coordinates of the input data points;
- ID is an identifier associated with the compiled {}
mapping to be applied;
- XOUT and YOUT are 1-dimensional arrays to receive the (transformed)
and
coordinates of the output data points;
- STATUS is an inherited error status variable.
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
{}
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.
Finally, before an application finishes, the statement:
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.
Copyright © 2000 Council for the Central Laboratory of the Research Councils