3 Interpretation of ARD Descriptions

 3.1 Values within the Pixel Mask
 3.2 Supplying an Initial Pixel Mask
 3.3 Bounding Boxes

After removal of all statement fields, and the insertion of any implicit .OR. operators, the fields in an ARD description are treated as a Fortran-like logical expression. Each keyword field forms a logical operand, acted upon by the adjoining operator fields. operators have their usual Fortran precedence (see Section 6). The order of evaluation can be changed by enclosing sub-expressions within parentheses as usual. The interpretation of operands depends on the type of keyword:

3.1 Values within the Pixel Mask

The ARD_WORK subroutine creates an array of integer values (the “mask”) which holds the result of evaluating the entire logical expression at each pixel. Positive integers represent .TRUE. (i.e. included pixels) and zero represents .FALSE. (i.e. excluded pixels).

Each keyword included in an ARD description is represented by a different positive integer. This provides the possibility for applications to differentiate between the different regions within an ARD description on the basis of the pixel mask alone.

3.1.1 Background Pixels

The .NOT. operator adds a few complications in that it requests pixels to be included which are not within a given region. For instance:

        .NOT.CIRCLE( 0, 0, 10)

includes all pixels which are not within the circle of radius 10 centred on the origin. If (say) the value 2 was used to represent the CIRCLE region, what value should be used to represent the pixels which are not within the circle? The solution adopted by ARD is to consider all pixels not within a region to be “background” pixels, and to reserve the value 1 to represent such pixels. All .NOT. operators in an ARD description use the value 1 to represent included background pixels. Note, ARD doesn’t know if a pixel is truly part of the background or not, it just assumes that all pixels selected by a .NOT. operator will be background. This gives rise to a possible anomaly which can be illustrated by the ARD description:

        .NOT. ( .NOT. CIRCLE( 0, 0, 10 ) )

One might expect this to be equivalent to the ARD description:

        CIRCLE( 0, 0, 10 )

but there will be a difference. The two ARD descriptions will store positive values at the same pixels (i.e. those within the circle), but the values stored will be different. In the first ARD description, the included pixels are generated by a .NOT. operator and so will be considered to be “background” pixels and will be represented by the value 1. In the second ARD description, the included pixels are generated directly by the CIRCLE keyword and will be represented by the value assigned to the keyword (which will be larger than 1).

The .EQV. operator can also cause background pixels to be included in the returned mask, and such background pixels are again represented by the value 1. The ARD description:

        CIRCLE( 0, 0, 10 ) .EQV. CIRCLE( 10, 0, 10)

selects pixels which are either within both circles or within neither circle. Pixels which are within neither circle form part of the background, and are represented by the value 1. Pixels which are within both circles are represented by the larger of the two values assigned to the two keywords.

3.1.2 Assignment of Keyword Values

The choice of which positive value to use to represent each keyword in the ARD description is controlled by the REGVAL argument supplied to the ARD_WORK routine. If a positive value is supplied for REGVAL then the first keyword in the ARD description (working from left to right) is assigned the supplied value. Successive values are assigned to the remaining keywords. An error is reported if REGVAL is supplied equal to 1. This is because 1 is reserved to represent background pixels and may not be used to represent keywords.

If a zero or negative value is supplied for REGVAL, then the array of pixel values supplied to ARD_WORK in argument MASK is examined and the maximum value found. This value is incremented by one and used to represent the first keyword in the ARD description (if the incremented value is less than 2, then 2 is used instead). Successive values are assigned to the remaining keywords.

There is one exception to these rules; pixels selected using an INPUT keyword (see section 3.2) are assigned the values of the corresponding pixels in the input mask supplied to ARD_WORK, irrespective of the position of the INPUT keyword in the ARD description. The inclusion of INPUT keywords within an ARD description does not effect the integer values used to represent other keywords. Thus if REGVAL is supplied equal to 2 and the ARD description is:

        CIRCLE( 0, 0, 10 ) .AND. ( INPUT .OR. CIRCLE( 0, 10, 10 ) )

then the CIRCLE(0,0,10) region is assigned the value 2 and the CIRCLE(0,10,10) region is assigned the value 3 (i.e. the INPUT keyword is not included in the count of keywords).

On return from ARD_WORK the REGVAL argument will hold a value one larger than the value assigned to the last keyword in the ARD description.

3.1.3 Pixels Included in Several Regions

If a given pixel falls within more than one region, then the largest of the values associated with the regions is stored at the pixel’s location. Specifically, the rules for determining the result of each operator are:

.AND.
- A zero is returned unless both operands are positive, in which case the larger of the two positive values is returned.
.OR.
- The larger of the two operand values is returned.
.XOR.
- If either operand is zero, then the value of the other operand is returned. If neither operand is zero, then zero is returned.
.EQV.
- If neither of the operands is zero, then the larger of the two operands is returned. If one of the operands is zero, then zero is returned. If both of the operands are zero, then the value 1 is returned.
.NOT.
- If the operand is positive, then zero is returned. If the operand is zero, then 1 is returned.

Let’s look at an example:

        CIR( 0, 0, 50 )
        CIR( 0, 0, 40 )
        CIR( 0, 0, 30 )
        CIR( 0, 0, 20 )
        CIR( 0, 0, 10 )

An implicit .OR. operator is assumed to exist between each of the CIRCLE keywords. Let’s assume that ARD_WORK is called with argument REGVAL set to 2. The CIR(0,0,50) keyword is evaluated first and causes a circular region of radius 50 to be filled with the value 2. Next, the CIR(0,0,40) keyword is evaluated. The value used to represent included pixels is incremented to 3, and a circular region of radius 40 is filled with this value, over-writing some of the 2’s which were written to the mask because of the previous keyword. Since the circular regions are concentric (both being centred on the (0,0) ), this will leave an annulus containing the value 2 around the edge of the circle containing value 3. The remaining keywords are processed in the same way, each successive keyword over-writing all but an annulus of the circle created by the previous keyword. The final mask consists of a set of concentric annuli, each of thickness 10. Working outwards from the centre, the annuli have the values 6, 5, 4, 3 and 2. The REGVAL argument will be returned holding 7.

One consequence of allowing larger values to “over-write” smaller values is that background pixels always get over-written by pixels which are selected by virtue of being within a keyword region. Consider the following (assuming that REGVAL is again supplied equal to 2):

        CIRCLE( 0, 0, 10 ) .AND. .NOT. CIRCLE( 0, 0, 5 )

This ARD description will be evaluated by first creating two intermediate masks, one containing the CIRCLE(0,0,10) region and another containing the .NOT.CIRCLE(0,0,5) region. These two masks will then be combined together using the .AND. operator to create the final mask. The first intermediate mask contains the value 2 at all pixels which are within the CIRCLE(0,0,10) region, and zero at all other pixels.

The second intermediate mask is initially set to hold the region CIRCLE(0,0,5). This means that pixels within the circle are given the value 3 and all others are given the value zero. The mask is then inverted to take account of the .NOT. operator. Pixels inside the circle which previously held the value 3 are changed to zero (indicating that these pixels have not been selected). Pixels outside the circle which previously held the value zero are assigned the value 1 (indicating that these pixels are background pixels).

The last stage is to combine the two intermediate masks together following the rules described above for an .AND. operator. Pixels which are further than 10 units from the origin (i.e. outside the CIRCLE(0,0,10) region) will hold zero in the first mask and 1 in the second mask, and so will be assigned a value zero in the final mask. Pixels which are between 5 and 10 units from the origin (i.e. inside the first circle but not the second) will have the value 2 in the first mask and the value 1 in the second. Both these values are positive and so the output mask pixel will also be positive. The rules for the .AND. operator above say that the positive value used will be the larger of the two values in the input masks. Thus the output mask pixels are assigned the value 2. Pixels which are less than 5 units from the origin will have the value 2 in the first mask and the value zero in the second mask, and so are assigned the value zero in the output mask. The final mask thus holds an annulus extending from radius 5 to radius 10 in which the pixels hold the value 2, all other pixels holding the value zero.

3.2 Supplying an Initial Pixel Mask

It may sometimes be necessary for applications to combine together pixel masks created from different ARD descriptions. To do this, the ARD descriptions should be processed in turn by ARD_WORK and they should use the “INPUT” keyword. This keyword refers to the pixel mask supplied to routine ARD_WORK in argument MASK; if a pixel holds a positive value in the supplied mask then the INPUT keyword is notionally .TRUE., and is notionally .FALSE. if the pixel value is zero or negative. This keyword can be used at any point in an ARD description, and can be included any number of times. A simple example of its use could be:

        .NOT. INPUT

which inverts the supplied mask. If the ARD description does not include any references to the INPUT keyword, then the application can force an INPUT keyword to be inserted at the start of the ARD description by supplying a .TRUE. value for ARD_WORK argument CONCAT. For instance, if CONCAT is supplied .TRUE., then the ARD description:

        BOX( 0, 0, 10, 10 ) .OR. CIR( 0, 0, 10 )

becomes

        INPUT BOX( 0, 0, 10, 10 ) .OR. CIR( 0, 0, 10 )

There is now no operator between the INPUT and BOX keywords, and so ARD inserts an implicit .OR. so that the final ARD description used is:

        INPUT .OR. BOX( 0, 0, 10, 10 ) .OR. CIR( 0, 0, 10 )

If the supplied ARD description had started with an operator, for instance:

        .AND.( BOX( 0, 0, 10, 10 ) .OR. CIR( 0, 0, 10 ) )

then there would be no need to insert an implicit .OR. after the INPUT keyword, and so the final used ARD description would be:

        INPUT .AND.( BOX( 0, 0, 10, 10 ) .OR. CIR( 0, 0, 10 ) )

To re-iterate, an INPUT keyword is inserted at the start of the ARD description only if the ARD description as supplied contains no INPUT keywords, and the ARD_WORK argument CONCAT is supplied .TRUE.. If either of these conditions is broken then the ARD description is left as supplied.

3.3 Bounding Boxes

To combine two large masks using a binary operator at every pixel can be wasteful of processor time, especially if not many of the pixels have actually been selected. To reduce this waste, ARD keeps track of the regions within the mask where the selected pixels are located, and only processes pixels in those regions. Precisely, ARD maintains a pair of “bounding boxes” throughout its evaluation of an ARD description. These are referred to as the internal and external bounding boxes. Each bounding box is a rectangular region of the mask. The internal bounding box contains all included pixels in the mask, but may also contain some excluded pixels. Conversely, the external bounding box contains all excluded pixels and may also contain some included pixels.

The upper and lower bounds of these boxes are returned to the calling application when the mask is complete. If an application is only interested in included pixels, it may then restrict its attention to the region of the data array contained within the internal bounding box (all pixels outside this box are guaranteed to be excluded). It is still necessary for the application to check mask pixels to see if they are included or excluded, but the checks can at least be restricted to the region of the internal bounding box. The external bounding box can be used in a similar way if the application is only interested in excluded pixels.

If all mask pixels are included (i.e. if there are no excluded pixels) then the external bounding box will be returned “null”, and the internal bounding box will be returned covering the entire mask. Likewise, if all mask pixels are excluded (i.e. if there are no included pixels) then the internal bounding box will be returned “null”, and the external bounding box will be returned covering the entire mask. Null bounding boxes are identified by the fact that the lower bound of each axis is greater than the corresponding upper bound. This condition should always be checked for before using a bounding box.