Jump Over Left Menu
Chapter 2: Graphical Output
The main objective of the Graphical Kernel System, GKS, is the production and manipulation of pictures (in a way that does not depend on the computer or graphical device being used). Such pictures vary from simple line graphs (to illustrate experimental results, for example), to engineering drawings, to integrated circuit layouts (using colour to differentiate between layers), to images representing medical data (from computerised tomographic (CT) scanners) or astronomical data (from telescopes) in grey scale or colour. Each of these various pictures must be described to GKS, so that they may be drawn.
In GKS, pictures are considered to be constructed from a number of basic building blocks. These basic building blocks, or primitives as they are called, are of a number of types each of which can be used to describe a different component of a picture. The five main primitives in GKS are:
- polyline: which draws a sequence of connected line segments.
- polymarker: which marks a sequence of points with the same symbol.
- fill area: which displays a specified area.
- text: which draws a string of characters.
- cell array: which displays an image composed of a variety of colours or grey scales.
Consideration of the cell array primitive is postponed until Chapter 12.
Associated with each primitive is a set of parameters which is used to define particular instances of that primitive. For example, the parameters of the text primitive are the string or characters to be drawn and the starting position of that string. Thus:
TEXT(X, Y, 'ABC')
will draw the characters ABC at the position (X, Y).
Although the parameters enable the form of the primitives to be specified, additional data are necessary to describe the actual appearance (or aspects) of the primitives. For example, GKS needs to know the height of a character string and the angle at which it is to be drawn. These additional data are known as attributes.
The attributes represent features of the primitives which vary less often than the form of the primitives. Attributes will frequently retain the same values for the description of several primitives. Once a suitable character height has been selected, for example, several character strings may be plotted using this character height (such as the labels on the axis of a graph).
In this chapter, we will look at the first four primitive types of GKS given above and their associated attributes.
In the figures, associated with the examples, the coordinate system used ranges from -5 to 34 in X and from -5 to 21 in Y.
The main line drawing primitive of GKS is the polyline which is generated by calling the function:
POLYLINE(N, XPTS, YPTS)
where XPTS and YPTS are arrays giving the N points (XPTS(1), YPTS(1)) to (XPTS(N), YPTS(N)). The polyline generated consists of N - 1 line segments joining adjacent points starting with the first point and ending with the last.
Why was the polyline chosen as the basic line drawing primitive in GKS? If we consider actual graphical devices, we can see that there are many ways of describing line segments. Incremental plotters require each individual increment of the approximated line segment to be specified. Other graphical devices rely on the concept of a current point. Only one end of each line segment need be specified and a line segment is drawn from the current point to the specified end point, which then itself becomes the current point. Yet other graphical devices expect a connected sequence of line segments to be specified.
In order to interface to all these devices, GKS uses an abstract description of a line. Unlike many graphics systems which rely on the concept of a current point with several related problems, GKS recognizes the frequency with which a set of connected line segments is drawn and, therefore, uses polyline as its basic line drawing primitive.
Suppose we wish to plot a graph of a set of data, maybe some experimental results. The data consist of a set of ordered pairs (X, Y), thus:
X 0.0 2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.4 17.0 17.3 Y 8.8 7.6 7.1 7.4 8.0 8.9 9.6 9.9 9.4 9.7 12.0 X 17.8 18.5 20.0 22.0 24.0 26.0 28.0 29.0 Y 14.0 16.1 17.0 17.0 16.0 13.9 13.1 13.2
The graph may be drawn by joining adjacent points with straight line segments. Thus we can plot our graph by the following sequence:
REAL XDK(19), YDK(19) DATA XDK/O.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.4, 17.0, 17.3, 17.8, 18.5, 20.0, 22.0, 24.0, 26.0, 28.0, 29.0/ DATA YDK/8.8, 7.6, 7.1, 7.4, 8.0, 8.9, 9.6, 9.9, 9.4, 9.7, 12.0, 14.0, 16.1, 17.0, 17.0, 16.0, 13.9, 13.1, 13.2/ POLYLINE(19, XDK, YDK)
This produces the output given in Figure 2-1. Note that in the examples in this book, only the GKS functions being illustrated, or those directly related to the example, are included. These examples on their own will not produce the output shown without the addition of introductory and terminating GKS functions, in the same way that they would not compile without the addition of a terminating FORTRAN 77 END statement. If you are interested in the appearance of a complete GKS program, one is given in Appendix C. The example used is that in Section 3.8; in Appendix C, all the introductory and terminating GKS functions are included and strict FORTRAN 77 is used.
Returning to our graph, in order to interpret it, we need to relate the graph to the coordinate data by drawing the axes. We may draw the axes with a polyline too. (In practice, a separate subroutine for drawing axes, using GKS functions, will often be available.) Without repeating the DATA statements above, we can extend our example:
REAL XA(3), YA(3) XA(1)=29 XA(2)=0 XA(3)=0 YA(1)=0 YA(2)=0 YA(3)=17 POLYLlNE(3, XA, YA) POLYLlNE(l9, XDK, YDK)
This will produce the output in Figure 2-2.
2.3 POLYLINE REPRESENTATION
Any complex picture will contain a number of polylines and it may be necessary to differentiate between polylines, This is done by using different representations for the polylines, Different representations are obtained by specifying different values for a polyline attribute associated with the polylines.
In the example above, we may wish to draw a constant Y line to enable points above the line to be identified. Even though this only requires a single line to be drawn, the polyline primitive can still be used. Note, also, that we do not need separate arrays to specify each polyline; we can reuse the arrays used to specify previous polylines. Thus, to draw the same picture with the line Y=9.5 added, we need only add:
YA(1)=9.5 YA(2)=9.5 POLYLINE(2. XA, YA)
This will generate the graph shown in Figure 2-3. (In future, separate arrays for each polyline will be used to simplify the examples.) This does not give us an ideal result as it is not easy to distinguish between our new line and the previously drawn line representing the data. We need to draw the two lines in such a way that we can distinguish them. We will do this by specifying each polyline with a different representation.
Let us consider the facilities available on actual devices for distinguishing lines. On a pen plotter with a single pen. lines may be distinguished by using different styles of line (e.g. solid. dashed, dotted) whereas on a pen plotter with more than one pen, different thickness pens may be used to draw with different widths. On devices capable of colour. lines may be drawn in different colours. In each case there is a way of distinguishing lines. The method of distinguishing lines must be described to GKS in a device independent way. GKS does this by having a single attribute called the polyline index. If a user wishes to distinguish between two polylines. he does this by defining each with a different polyline index. The exact representation that the polyline will have on a specific device depends on what facilities are available. This will be described in more detail in Chapter 7. There is also a way of individually controlling the aspects that distinguish lines. that has advantages in certain applications. This is described in Chapter 13. For the moment, all that we need to know is that poly lines with different polyline index values associated with them can, and normally will, appear differently on the actual display used. The polyline index is set by the GKS function:
SET POLYLINE INDEX(N)
This sets the polyline index to the value N for all subsequent polylines until its value is reset by another call of this function.
In this chapter, we will only consider default values for the representations; later we will see how to specify our own. We will assume that polyline representation 1 is a solid line and polyline representation 2 is a dashed line. For both representations, a standard linewidth and colour are used. In the pictures drawn so far, the default value of the polyline index has been used which is, in fact, 1.
We can now draw our graph far better by distinguishing the line representing the data from the others.
First, we will define a subroutine AXES, which will be used in several places:
SUBROUTINE AXES(XMAX, YMAX) REAL XA(3), YA(3) XA(1)=XMAX XA(2)=0 XA(3)=0 YA(1)=0 YA(2)=0 YA(3)=YMAX POLYLINE(3, XA, VA) RETURN END
Then, we may write our example as:
REAL XDK(l9), YDK(19), XB(2), YB(2) XB(1)=0 XB(2)=29 YB(1)=9.5 YB(2)=9.5 SET POLYLINE INDEX(1) AXES(29, 17) POLYLINE(2, XB. YB) SET POLYLINE INDEX(2) POLYLINE(19, XDK, YDK)
This produces the results shown in Figure 2-4. In the example, as good practice, we set the polyline index to 1 explicitly before the first polyline (drawn by AXES), although this will not alter the polyline's appearance as the default value is 1. Note that the polyline specified by XB and YB is also drawn using a polyline index value of 1 as the polyline index has not been reset. In contrast, the line representing the data is drawn using a polyline index value of 2 to differentiate it from the axes. This method of controlling the appearance of primitives is a very powerful feature. For example, a high level graphics routine to perform contouring will need to distinguish between contours, whether to highlight contours above or below a certain height or to highlight every nth contour. By using a different polyline index to draw each set of contours in the high level routine, the application program which uses it may choose the representation for each index to achieve the desired contour map.
Instead of drawing lines through a set of points, we may wish just to mark the set of points. GKS provides the primitive polymarker to do just this. A polymarker is generated by the function:
POLYMARKER(N, XPTS, YPTS)
where the arguments are the same as for the polyline function, namely XPTS and YPTS are arrays giving the N points (XPTS(1), YPTS(1)) to (XPTS(N), YPTS(N)). Polymarker places a centred marker at each point. GKS recognizes the common use of markers to identify a set of points in addition to marking single points and so the marker function is a polymarker. We may now, as shown in Figure 2-5, plot the data points in our example rather than the line through the points. This is done by simply replacing the appropriate call to POLYLINE by a call to POLYMARKER. thus:
AXES(29, 17) POLYLINE(2, XB. YB) POLYMARKER(l9, XDK, YDK)
Of course, we may wish both to identify the set of points and plot the lines through them, which is of course possible:
AXES(29, 17) POLYLINE(2, XB. YB) POLYMARKER(l9, XDK, YDK) POLYLINE(19, XDK, YDK)
This composite output is shown in Figure 2-6. In a similar manner to polyline, GLKS provides a facility to distinguish different sets of points. Polymarkers may be specified with different representations. This is done by assigning different values to a polymarker attribute called the polymarker index.
The polymarker index is set by the GKS function:
SET POLYMARKER INDEX(N)
where N is the desired value of the polymarker index. We will assume that polymarker representation 1 is an asterisk, polymarker representation 2 is a circle and polymarker representation 3 is a plus sign, all in a standard size and colour. Let us introduce a further set of data we wish to plot on our graph relating the two variables X and Y:
X 15.7 17.0 17.7 17.3 15.3 13.0 11.0 9.0 7.0 4.7 Y 7.0 6.1 5.0 3.8 3.0 2.7 3.0 3.6 4.2 5.2
We will draw the two sets of points with different representations so that we can distinguih them:
REAL XW(10), YW(10) DATA XW/15.7, 17.0, 17.7, 17.3, 15.3, 13.0, 11.0, 9.0, 7.0, 4.7/ DATA YW/ 7.0, 6.1, 5.0, 3.8, 3.0, 2.7, 3.0, 3.6, 4.2, 5.2/ SET POLYLINE INDEX(1) AXES(29. 17) SET POLYMARKER INDEX(1) POLYMARKER(19, XDK, YDK) SET POLYMARKER INDEX(2) POLYMARKER(10, XW, YW)
This is shown in Figure 2-7. Note that the second set of data is not single valued but this does not cause any problems.
2.5 FILL AREA
There are many applications for which line drawings are insufficient. The design of integrated circuit layouts requires the use of filled rectangles to display a layer. Animation systems need to be able to shade areas of arbitrary shape. Other applications using colour only realize their full potential when they are able to use coloured areas rather than coloured lines.
At the same time, there are now many devices which have the concept of an area which may be filled in some way. These vary from intelligent pen plotters which can cross-hatch an area to raster displays which can completely fill an area with a single colour or in some cases fill an area by repeating a pattern.
GKS provides a fill area function to satisfy the application needs which can use the varying device capabilities. Defining an area is a fairly simple extension of defining a polyline. An array of points is specified which defines the boundary of the area. If the area is not closed (i.e. the first point is not the same as the last point), the boundary is the polyline defined by the points but extended to join the last point to the first point. A fill area may be generated by invoking the function:
FILL AREA(N, XPTS, YPTS)
where, as usuaL XPTS and YPTS are arrays giving the N points (XPTS(1), YPTS(1)) to (XPTS(N), YPTS(N)).
Let us extend our original set of data to describe a closed area. Nineteen data points were previously defined to which we add a further 24.
X 28.8 27.2 25.0 23.0 21.5 21.1 21.5 22.8 24.1 25.1 Y 12.3 11.5 11.5 11.5 11.2 10.5 9.0 8.0 7.0 5.1 X 25.2 24.2 22.1 20.0 18.0 16.0 14.0 12.0 10.0 8.0 Y 3.6 1.9 1.1 0.9 0.7 0.8 1.0 1.0 1.2 1.8 X 6.1 4.2 3.0 1.3 Y 2.1 2.9 4.1 6.0
Like the other primitives we have considered. fill area has a representation accessed by a fill area attribute called the fill area index.
The fill area index is set by the function:
SET FILL AREA INDEX(N)
where N is the desired value of the fill area index. Filled areas may be distinguished by their fllling style (called interior style in GKS) and colour. Let us assume that fill area representation 1 is interior style HOLLOW and that fill area representation 2 is interior style SOLID, each in standard colour.
We can now plot our extended set of data which represents an area. We will use fill area representation 1:
REAL XDK(43). YDK(43) DATA XDK/0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.4, 17.0, 17.3, 17.8, 18.5, 20.0, 22.0, 24.0, 26.0, 28.0, 29.0, 28.8, 27.2, 25.0, 23.0, 21.5, 21.1, 21.5, 22.8, 24.1, 25.1, 25.2, 24.2, 22.1, 20.0, 18.0, 16.0, 14.0, 12.0, 10.0, 8.0, 6.1, 4.2, 3.0, 1.3/ DATA YDK/ 8.8, 7.6, 7.1, 7.4, 8.0, 8.9, 9.6, 9.9, 9.4, 9.7, 12.0, 14.0, 16.1, 17.0, 17.0, 16.0, 13.9, 13.1, 13.2, 12.3, 11.5, 11.5, 11.5, 11.2, 10.5, 9.0, 8.0, 7.0, 5.1, 3.6, 1.9, 1.1, 0.9, 0.7, 0.8, 1.0, 1.0, 1.2, 1.8, 2.1, 2.9, 4.1, 6.0/ SET POLYLINE INDEX(1) AXES(29. 17) SET FILL AREA INDEX(1) FILL AREA(43. XDK. YDK)
This produces the output like a duck given in Figure 2-8. We can see that for interior style HOLLOW, only the boundary has been drawn. It is interesting to note, however, the contrast with the result that would have been obtained if the last two statements containing fill area functions had contained the corresponding polyline functions:
SET POLYLINE INDEX(1) POLYLINE(43. XDK. YDK)
In this case, the output would be as shown in Figure 2-9. This illustrates the fact that the fill area primitive is a true area primitive even if it is drawn by lines. The last point is joined to the first by the fill area function to complete the outline.
If the fill area example were drawn using fill area representation 2, i.e. the last two statements were:
SET FILL AREA INDEX(2) FILL AREA(43. XDK. YDK)
we would then get the output given in Figure 2-10. Let fill area representation 3 be interior style HATCH, using a diagonal hatch, and a standard colour. The fill area primitive is defined to fill the area only and so does not include drawing the boundary (apart from interior style HOLLOW for obvious reasons!). Thus, if the last two lines of our example were:
SET FILL AREA INDEX(3) FILL AREA(43, XDK, YDK)
the picture would be as shown in Figure 2-11. If we wish to include the boundary, we may additionally draw a polyline around the area. Here we must be careful. As we saw earlier, the fill area function will join the last point to the first (if they are not the same) to define the area but the polyline function, of course, will not. Therefore, if we wish to draw the boundary by means of a polyline, we must ensure that the last point of the set is the same as the first to achieve the desired result. In our example set of data, this means that we must add a 44th point which is the same as the first:
Then we can again replace our last two lines by:
SET FILL AREA INDEX(3) FILL AREA(43, XDK, YDK) POLYLINE(44, XDK, YDK)
to give the hatched duck shown in Figure 2-12. So far we have only considered filling simple shapes. Suppose we add even more data to our example set. Let us concatenate our other set of data (XW, YW), introduced to illustrate the polymarker index in Section 2.4, by making the 44th point of our data the first point of that set, the 45th point the second and so on:
DO 100 I=1,10 XDK(I+43)=XW(I) 100 YDK(I+43)=YW(i)
This gives us 53 points. If we draw it with fill area representation 1, which uses interior style HOLLOW, the output would be as shown in Figure 2-13. Our area is now complex. If we were to fill it with fill area representation 2, which uses interior style SOLID, which areas would be filled? What is the inside of the area? GKS is not the first system to face this problem. The rule used to decide is that if a line drawn from any point to infinity crosses the boundary an even number of times (including zero), the point is outside but if the line crosses the boundary an odd number of times, the point is inside. We can now confidently plot our data with fill area representation 2, giving the output shown in Figure 2-14.
2.6 THE DUCK
At this point, it is convenient to write a complete subroutine to draw our duck, for use in examples in later chapters. We will draw our duck as two polylines defined by the arrays of points XDK, YDK for the outline and XW, YW for the wing. We have already seen the data and so we can write our subroutine thus:
SUBROUTINE DUCK REAL XDK(44), YDK(44), XW(10), YW(10) DATA XDK/ 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.4, 17.0, 17.3, 17.8, 18.5, 20.0, 22.0, 24 0, 26,0, 28.0, 29.0, 28.8, 27.2, 25.0, 23.0, 21.5, 21.1, 21.5, 22.8, 24.1, 25 1, 25.2, 24.2, 22.1, 20.0, 18.0, 16.0, 14.0, 12.0, 10.0, 8.0, 6.1, 4.2, 3.0, 1.3, 0.0/ DATA YDK/ 8.8, 7.6, 7.1, 7.4, 8.0, 8.9, 9.6, 9.9, 9.4, 9.7, 12.0, 14.0, 16.1, 17.0, 17.0, 16.0, 13.9, 13.1, 13.2, 12.3, 11.5, 11.5, 11.5, 11.2, 10.5, 9.0, 8.0, 7.0, 5.1, 3.6, 1.9, 1.1, 0.9, 0.7, 0.8, 1.0, 1.0, 1.2, 1.8, 2.1, 2.9, 4.1, 6.0, 8.8/ DATA XW/ 15 7, 17.0, 17.7, 17.3, 15.3, 13.0, 11.0, 9.0, 7.0, 4.7/ DATA YW/ 7.0, 6.1, 5.0, 3.8, 3.0, 2.7, 3.0, 3.6, 4.2, 5.2/ POLYLINE(44, XDK, YDK) POLYLINE(10, XW, YW) RETURN END
Note that we have not included the axes in the subroutine as we do not always wish the axes to be drawn and, in any case, we already have a subroutine to draw them. To draw the duck with a set of axes we may write:
AXES(29. 17) DUCK
The output is illustrated in Figure 2-15.
So far we have not attempted to put a title on our pictures. To do this, GKS has a text primitive which is used to title pictures or place labels on them as appropriate. A text string may be generated by invoking the function:
TEXT(X, Y, STRING)
where (X, Y) is the text position and STRING is a string of characters.
However, text is more complicated than the other primitives that we have examined. Everybody is used to good quality text in books whether it is the printed text of the book itself or text within the context of diagrams. Text is printed at different sizes, in different fonts, at different orientations and at different spacings. Graphics devices. on the other hand, are often not good at text; indeed some are not capable of text at all. Those that do often only have a restricted number of sizes. one or perhaps two orientations, and a single font.
What are the requirements of graphics applications? If a picture is produced as one of a (possibly rapidly changing) sequence on the screen of an interactive graphics device, it is most likely that quickly produced text is required without placing constraints on quality. On the other hand, if a high quality hardcopy picture is being produced it is likely that text of a similar high quality would be required. If such a picture were being previewed on an interactive device before final hardcopy was produced, a reasonable approximation to the high quality text would be needed.
GKS attempts to match these requirements with its text primitive. Each of the other primitives that we have examined has had a single attribute which controls the aspects of its appearance (via a representation). Since text is more complex, its appearance is affected by a larger number of aspects. Some of these are too important to be controlled by a representation. At the same time, they do not vary with every text string that is output. (Those that usually do are supplied as parameters to the text primitive; the text position and the character string itself.) These important aspects are the character height, character up vector, text path, and text alignment.
In GKS, they are each attributes of text which may be individually assigned values. Of course, text also has a representation, accessed by the text index, which will be described later (in Section 2.7.2).
An example of the text primitive is:
TEXT(6, 3, 'A Character String')
which produces the output shown in Figure 2-16.
2.7.1 Text Attributes
The character height attribute determines the height of the characters in the string. Since a character in a font will have a designed aspect ratio, the character height also determines the character width. The character height is set by the function:
SET CHARACTER HEIGHT(H)
where H is the character height. For example. Figure 2-17 would result if the following were executed:
SET CHARACTER HEIGHT(1) TEXT(-2, 11. 'Character Height 1') SET CHARACTER HEIGHT(2) TEXT( -2. 5, 'Character Height 2')
The character up vector is perhaps the most important text attribute. Its main purpose is to determine the orientation of the characters. However, it also sets a reference direction which is used in the determination of text path and text alignment. The character up vector specifies the up direction of the individual characters. It also specifies the orientation of the character string in that. by default, the characters are placed along the line perpendicular to the character up vector. The function:
SET CHARACTER UP VECTOR(X, Y)
is used for setting the character up vector. X and Y are the offsets from the text position of the up direction of the characters. Specifying a vector is just a way of specifying an angle. The magnitude of the vector is not used. Thus:
SET CHARACTER UP VECTOR(-1, 1)
Has the same effect as:
SET CHARACTER UP VECTOR(-15, 15)
Both cause subsequent character strings to be plotted at 45 degrees to the horizontal (for the default value of text path, see below). Thus:
SET CHARACTER UP VECTOR(-1, 1) TEXT(6, 3, 'A Character String')
would generate the text string shown in Figure 2-18. Not all character sets are left to right character sets, nor do we always require the character path to be at right angles to the character up vector. For example, a y axis is sometimes labelled using a hotel sign, that is, where letters are placed one underneath the other. GKS provides a text path attribute to solve both these problems. It is set by the function:
SET TEXT PATH(PATH)
where PATH has one of the four values: RIGHT, LEFT, UP, and DOWN. These are all relative to the direction defined by the character up vector (see Figure 2-19). RIGHT (the default) causes the characters to be placed one after another along the line perpendicular (in a clockwise direction) to the character up vector. LEFT causes characters to be placed in the opposite direction and so is suitable for right to left character sets. DOWN causes characters to be placed one underneath the other and UP causes them to be placed one on top of the other. For example, using the default vertical character up vector, the sequence:
SET CHARACTER UP VECTOR(0, 1) SET TEXT PATH(DOWN) TEXT(10, 17, 'GRAND HOTEL')
would produce the output given in Figure 2-20, whereas:
SET CHARACTER UP VECTOR(1, 6) SET TEXT PATH(DOWN) TEXT(12, 16, 'HOTEL PISA')
where the character up vector is not vertical, would produce the output shown in Figure 2-21.
As we know, the first parameter of the text primitive is the text position, In the examples above, the text position has been specified but has not been marked on the pictures produced. This is for two reasons, Firstly, the text position will not be marked on output produced by GKS, Secondly, on account of the text attribute to be described next, the text position does not always occupy the same position in relation to the plotted character string.
This text attribute is text alignment. It allows the complete character string to be aligned in different ways with respect to the text position. Text may be aligned separately along horizontal and vertical axes. (Note that these are relative to the character up vector and not necessarily horizontal and vertical. The vertical axis is orientated in the direction of the character up vector and the horizontal axis is perpendicular to it.) Text alignment is set by the function:
SET TEXT ALIGNMENT(HORIZ, VERT)
where HORIZ and VERT are the horizontal and vertical alignments.
Along the horizontal axis, text may be aligned to the LEFT, CENTRE, or RIGHT. If the text is aligned to the LEFT, it means that th character string is aligned with the left hand side through the text position. RIGHT is similarly defined, with the right hand side through th text position. For example, if we mark the text position with an asterisk (and ignore the vertical component of alignment), then:
SET CHARACTER HEIGHT(1.25) SET TEXT ALIGNMENT(LEFT, BASE) TEXT(15, 11, 'Left Aligned') SET TEXT ALIGNMENT(RIGHT, BASE) TEXT(15, 5, 'Right Aligned')
would give the output shown in Figure 2-22. The horizontal alignment value CENTRE aligns the character string with the text position half way between the left and right extremes of the string.
Text may also be aligned in a number of ways along the vertical axis: TOP, CAP, HALF, BASE, and BOTTOM. The values TOP and BOTTOM align the appropriate extremes of the character string along the vertical axis in a similar manner to LEFT and RIGHT along the horizontal axis. The values CAP, HALF, and BASE align internal font lines of the characters in the string along the vertical axis. Of these, BASE is the most important being an alignment with the baseline of the characters, that is the line on which upper case characters sit.
These values have been described generally in terms of the horizontal text paths. The definitions only need extending slightly to have reasonable interpretations for all text paths, as is illustrated by the following example (where BOX is a subroutine to draw a box described by the limits in x followed by the limits in y):
BOX(-1, 30, 14, 17.25) SET CHARACTER HEIGHT(2.25) SET TEXT ALIGNMENT(LEFT, BASE) SET TEXT PATH(RIGHT) TEXT(0, 14.5, 'A. B. JONES') SET CHARACTER HEIGHT(0.9) SET TEXT ALIGNMENT(RIGHT, CAP) TEXT(29, 16.75, 'TOYS') SET TEXT ALIGNMENT(RIGHT, BASE) TEXT(29, 14.5, 'SWEETS') SET CHARACTER HEIGHT(1) SET TEXT ALIGNMENT(CENTRE, TOP) SET TEXT PATH(DOWN) TEXT(3, 9, 'HOTEL') SET TEXT PATH(RIGHT) TEXT(23.5, 7, 'PLEASE') TEXT(23.5, 5, 'PAY') TEXT(23.5, 3, 'HERE') SET TEXT ALIGNMENT(LEFT, BOTTOM) SET TEXT PATH(DOWN) TEXT(11, -1, 'SAVINGS') TEXT(13, -1, 'BANK')
This would produce the output shown in Figure 2-23, In the earlier example (see Figure 2-22), we used the default value of text path RIGHT). If we had used the value LEFT for text path by inserting:
SET TEXT PATH(LEFT)
at the start of the example, we would have obtained the results shown in Figure 2-24. The character strings have been reversed because of theo pposite text path, but they each occupy the same space as before. The effect of text alignment has not been affected by the value of text path.
However, the normal text alignments are dependent upon text path. For a text path of RIGHT, the normal horizontal text alignment is LEFT but for a text path of LEFT (usually used in connection with a right to left character set) the normal horizontal text alignment is RIGHT. In order that the expected text alignment is achieved for each text path, when text alignment has not been explicitly set, a value of NORMAL for each of the horizontal and vertical components exists. When a text alignment component has the value NORMAL (which is the default), the normal text alignment for the text path is used. If a text alignment component has another value, that value is used irrespective of text path. The following example illustrates the NORMAL alignments for each text path:
SET CHARACTER HEIGHT(1.75) SET TEXT ALIGNMENT(NORMAL, NORMAL) SET TEXT PATH(RIGHT) TEXT(16, 11, 'Right') SET TEXT PATH(LEFT) TEXT(12, 11, 'Left') SET TEXT PATH(DOWN) TEXT(14, 9, 'Down') SET TEXT PATH(UP) TEXT(14, 13, 'Up')
which gives the output shown in Figure 2-25.
2.7.2 Text Representation
As mentioned earlier, text also has a representation accessed via the text index. The text index is set by the function:
SET TEXT INDEX(N)
where N is the desired value of the text index. Let text representation 1 be a roman font at STROKE precision (the highest quality), using a unit character expansion factor, zero spacing and a standard colour. Let text representation 2 be the same except that it uses CHAR precision (medium quality), and let text representation 3 be the same except that it uses STRING precision (the lowest quality). Then the following example:
SET CHARACTER UP VECTOR(-1, 1.732) SET TEXT PATH(RIGHT) SET TEXT ALIGNMENT(LEFT, BASE) SET TEXT INDEX(1) TEXT(8, 4, 'Angled Text')
would give the output shown in Figure 2-26, which is an accurate representation of the requested text. However, if we use text index 3, we get the output shown in Figure 2-27, This is because the STRING precision text does not need to use all the text attributes, It is the text that will often be used on interactive devices where it needs to be produced quickly, The highest precision text is that which would be used for the high quality output referred to earlier. To preview this high precision text we can use the medium precision text; using text index 2 gives the output shown in Figure 2-28. Here the position of the characters is precise but the orientation of the individual characters is upright This gives a reasonable representation of the text suitable for preview but does not take the time required to produce the final copy.
Suppose text representation 4 is the same as text representation 1 but uses an italic font Then using text index 4 in the above example will give the output shown in Figure 2-29.
These examples show both the flexibility of the text primitive of GKS and how text in GKS answers the application requirements referred to earlier.
2.8 PRIMITIVES AND ATTRIBUTES
In this chapter we have examined the four primitives polyline, polymarker, fill area, and text. One attribute has been described for each primitive except text for which five have been described. By suitable combinations of primitives and values of primitive attributes, quite complex pictures may be described to GKS with suitable annotations and titles, as is shown in the following example:
REAL XNEWDK(44), YNEWDK(44), XNEWW(10), YNEWW(10) PI=4*ATAN(1) XC=45 YC=45 R=30 MOVE DUCK(XC, YC, R, 5*PI/6, XNEWDK, YNEWDK, XNEWW, YNEWW) SET POLYLINE INDEX(1) POLYLINE(44, XNEWDK, YNEWDK) POLYLINE(10, XNEWW, YNEWW) MOVE DUCK(XC, YC, R, PI/2, XNEWDK, YNEWDK, XNEWW, YNEWW) SET POLYLINE INDEX(2) POLYLINE(44, XNEWDK, YNEWDK) POLYLINE(10, XNEWW, YNEWW) MOVE DUCK(XC, YC, R, PI/6, XNEWDK, YNEWDK, XNEWW, YNEWW) SET POLYMARKER INDEX(1) POLYMARKER(44, XNEWDK, YNEWDK) SET POLYMARKER INDEX(3) POLYMARKER(10, XNEWW, YNEWW) MOVE DUCK(XC, YC, R, -PI/6, XNEWDK, YNEWDK, XNEWW, YNEWW) SET FILL AREA INDEX(2) FILL AREA(44, XNEWDK, YNEWDK) MOVE DUCK(XC, YC, R, -PI/2, XNEWDK, YNEWDK, XNEWW, YNEWW) SET FILL AREA INDEX(3) FILL AREA(44, XNEWDK, YNEWDK) SET POLYLINE INDEX(1) POLYLlNE(44, XNEWDK, YNEWDK) MOVE DUCK(XC, YC, R, -5*PI/6, XNEWDK, YNEWDK, XNEWW, YNEWW) FILL AREA(44, XNEWDK, YNEWDK) SET POLYLINE INDEX(2) POLYLlNE(44, XNEWDK, YNEWDK) SET TEXT INDEX(1) SET CHARACTER HEIGHT(7.5) SET TEXT ALIGNMENT(RIGHT, HALF) TEXT(23.5, 45, 'G') SET CHARACTER HEIGHT(3) SET TEXT ALIGNMENT(LEFT, HALF) TEXT(23.5, 45, 'RAPHICAL') SET TEXT ALIGNMENT(RIGHT, HALF) TEXT(59, 45, 'DUC) SET CHARACTER HEIGHT(7.5) SET TEXT ALIGNMENT(LEFT, HALF) TEXT(59, 45, 'KS')
where MOVE DUCK calculates the coordinates of the duck and wing, when the centre of the duck is placed at a point on a circle with centre (XC,YC) and radius R at an angle THETA from the horizontal radius. The new coordinates of the duck are returned in the arrays XNWDK and YNWDK and those of the wing are returned in the arrays XNWW and YNWW, thus:
SUBROUTINE MOVE DUCK(XC, YC, R, THETA, XNWDK, YNWDK, XNWW, YNWW) REAL XNWDK(44), YNWDK(44), XNWW(10), YNWW(10) REAL XDK(44), YDK(44), XW(10), YW(10) DATA initialisc XDK. YDK, XW, YW as earlier XPOS=XC + R*COS(THETA) YPOS=YC + R*SIN(THETA) DO 100 I= 1,44 XNWDK(I)=XDK(I)-14.5 + XPOS 100 YNWDK(I)=YDK(I)-8.85 + YPOS DO 200 I = I,10 XNWW(I)=XW(I)-14.5 + XPOS 200 YNWW(I)=YW(I)-8.85 + YPOS RETURN END
The output is shown in Figure 2-30. A complete GKS program based on this example is given in Appendix C.