Contact us Heritage collections Image license terms
HOME ACL ACD ICF SUS DCS G&A STARLINK Literature
Further reading □ OverviewContentsPrefaceNotation1. Introduction2. Graphical output3. Coordinates4. Segments and Attributes5. Input devices6. Interaction styles7. Workstations8. Environment9. Input control10. Segment storage11. Metafiles12. Further facilities13. Individual attributesA. AbbreviationsB. Language bindingC. Complete programIndex
C&A INF CCD CISD Archives Contact us Heritage archives Image license terms

Search

   
ACDLiteratureBooksGKS
ACDLiteratureBooksGKS
ACL ACD C&A INF CCD CISD Archives
Further reading

OverviewContentsPrefaceNotation1. Introduction2. Graphical output3. Coordinates4. Segments and Attributes5. Input devices6. Interaction styles7. Workstations8. Environment9. Input control10. Segment storage11. Metafiles12. Further facilities13. Individual attributesA. AbbreviationsB. Language bindingC. Complete programIndex

Chapter 5: Graphical Input Devices

5.1 INTRODUCTION

So far, this book has been primarily concerned with the output of graphical images. To a large extent, it has not been important to ask whether anyone is looking at the result at the time the image is being generated. (If you wish to consider GKS as a graphical output system only, you should continue reading at Chapter 7.)

This chapter concentrates on the person who sees an image and reacts by rotating, moving, pressing or switching some piece of hardware in order to change the behaviour of an application program. This person's actions may simply be transferring data values to the program or may affect its flow of control in a more radical and interactive way. We refer to this person as the operator, to distinguish him from the other user - the programmer.

Not until Chapter 4 was some interactive programming done and, there, the FORTRAN READ statement was used to input values to the program to control the graphical information being displayed. An example was given in Section 4.1 where an (X, Y) value was read and used to place the duck at the next required position on the pond.

Most displays will have hardware which allows graphical information to be entered directly to the system rather than always using the keyboard. For example, a storage tube will often have a pair of crosshairs to indicate positions on the display screen and these provide an alternative to the keyboard for inputting positional information. However, the variety of input hardware is very great and input data is supplied in many different forms. These different forms of data must be organized in a uniform way, that does not depend on particular physical devices, to match the needs of application programs.

In GKS, the data that can be input to the program by the operator are divided into six different types and six classes of logical input device are defined corresponding to these data types. Just as, when output was described, we did not talk about physical output devices and their characteristics so here we will not discuss physical input devices in detail but we will concentrate on the logical input devices. We will show how physical input devices are mapped onto these logical devices in Chapter 7.

The six classes of logical input device in GKS are:

  1. locator: which inputs a position - an (X, Y) value.
  2. pick: which identifies a displayed object.
  3. choice: which selects from a set of alternatives.
  4. valuator: which inputs a value.
  5. string: which inputs a string of characters.
  6. stroke: which inputs a sequence of (X, Y) positions.

Locator and pick supply input data directly related to some feature of the display. In contrast, the other input devices supply quite simple data not directly related to the display. However, they are frequently generated by physical devices associated with graphics displays and can be conveniently echoed on these graphics displays. In addition these data are commonly required by interactive programs.

Note that these are logical input devices associated with the normalized device having the NDC unit square as its display area. Physical devices will map into one or more of these logical devices. In the positioning of the duck in Section 4.1, the READ statement has input an (X, Y) value and effectively acts as a kind of locator device. However, it does not correspond precisely with the logical locator device described below. Typical physical devices that are often used to map onto these logical devices are:

  1. locator: crosshairs and thumbwheels on a storage tube.
  2. pick: lightpen hitting an object displayed on the screen.
  3. choice: button box or menu selection using a lightpen.
  4. valuator: potentiometers or inputting a value from a keyboard.
  5. string: keyboard input of a line of text.
  6. stroke: tablet input.

The precise description of the logical input devices will be given later in this chapter. First, we must describe how they operate.

5.2 REQUEST MODE

As well as the type of input, we also need to specify when it takes place and under whose control. Discussion of styles of interaction will be deferred until Chapter 6. In this chapter, we will just use the type of input called REQUEST mode which corresponds almost identically to the type of input used in FORTRAN.

In a FORTRAN program, when a READ statement is executed, the FORTRAN program is suspended and waits for the input system to provide the values that have been requested. Execution of the FORTRAN program continues when the input system delivers the values to the FORTRAN program. Effectively, either the FORTRAN program or the input system is active but not both together. This corresponds directly to REQUEST mode in GKS. A program will REQUEST an input from a logical input device and will then wait while the logical input device takes over. Once the logical input device has obtained the required data, it returns it to the GKS program and effectively goes back to sleep. Either the GKS program is executing or the logical input device is active but never both together (in REQUEST mode).

One constraint this imposes is, of course, that never more than one logical input device can be active at a time. We shall see in Chapter 6 how the GKS program can be executed in modes whereby both it and the logical input devices are active at the same time and how GKS allows several logical input devices to be active together. However, while we are mainly concerned with the characteristics of the logical input devices themselves, we will restrict ourselves to describing these as they would be used in REQUEST mode. It is sufficient to say at this point that all logical input devices can be used in the other more versatile modes.

The form of the GKS function for REQUEST input is:

REQUEST XXX(WS, DV, ST, .......)

The XXX part of the function name defines the class of logical input device (LOCATOR, PICK etc) and the first two parameters specify the specific device of that class from which input is requested; WS specifies the workstation (see Chapter 7) on which the device is located and DV specifies which of the devices of the class it is. (It is possible to have more than one logical input device of a particular type.) The third parameter, ST, is a status indicator which returns information concerning how successful the logical device was in providing the requested values. It will be described in Chapter 6. In the next few sections, we will concentrate on the parameters specific to each logical input device.

5.3 LOCATOR

The LOCATOR logical input device returns a single position to the application program. The program can initiate this in REQUEST mode by calling the GKS function:

REQUEST LOCATOR(WS, DV, ST, NORMTR, XPOS, YPOS)

The REQUEST LOCATOR function returns a position (XPOS, YPOS) in world coordinates and a normalization transformation NORMTR which was used to map back from normalized device coordinates to world coordinates.

The LOCATOR logical input device obtains a position in NDC space from the physical device. It is possible that the picture being displayed has been constructed using a number of different window to viewport transformations. The logical input device identifies which viewport the position in NDC space lies within and uses this to transform the position back to world coordinates.

The example in Section 41, which repositioned the duck on the pond, could now use a LOCATOR device to define the position as follows:

      SET WINDOW(1, XWMIN, XWMAX, YWMIN, YWMAX) 
      SET VIEWPORT(1, XVMIN, XVMAX, YVMIN, YVMAX) 
      SELECT NORMALIZATION TRANSFORMATION(1)
 100  CONTINUE 
      REQUEST LOCATOR(WS, DV, ST, NT, X, Y) 
      NEW FRAME 
      DRAW BACKGROUND 
      DRAW DUCK AT(X, Y) 
      GOTO 100

It is assumed that the operator has specified a position within the viewport used to define the picture so that the value of NT returned is 1. Figure 5-1 shows what the operator might see. The position of the duck is defined by the top of its tail. In the left hand part of the figure, the new position is identified by the crosshairs. In the right part of the figure, the duck is redrawn at the new position specified. This same example could have been redefined using segments as was done in Chapter 4.

5.3.1 Several Viewports

Commonly, several normalization transformations are used by the program. For example, Figure 5-2 shows a picture where the duck is drawn in viewport 1 and the word QUIT is displayed in viewport 2. In this case, we would like the operator to be able to input a locator value in either viewport. If the locator input is in the upper viewport, the duck is drawn at the position defined by the locator whereas, if the locator input is in the lower viewport, this part of the program is completed and control is returned. Assuming window to viewport transformations have already been defined, where normalization transformation 1 is the upper and normalization transformation 2 is the lower, the program would be:

Figure 5-1
 100  CONTINUE 
      REQUEST LOCATOR(WS, DV, ST, NT, X, Y) 
      IF(NT .EQ. 2) RETURN 
      DRAW DUCK AT(X, Y) 
      GOTO 100

5.3.2 Overlapping Viewports

So far, all the locator input examples assumed that the viewports did not overlap. However, there is no reason why viewports should not overlap. In fact, this always occurs as normalization transformation 0 is defined to map the unit square in world coordinates to the whole of the NDC space unit square (see Section 3.8). This ensures that there is always one viewport which a locator input lies within. In the case where two viewports overlap, we need to define which normalization transformation is used to determine the mapping from NDC back to world coordinates.

Consider an example (see Figure 5-3) in which viewport 1 is the area where the main picture is to be drawn. Viewport 2 is an area where a detail of the main picture is being drawn. Viewport 3 defines a set of options which can be identified by their Y coordinates. For example, the MOVE operation could be defined by specifying a position in either the detailed picture or the main one. As the detailed picture has a viewport which is also part of the main picture's viewport, it is unclear which viewport would be used for the transformation back to world coordinates.

QUIT

Figure 5-2

MOVE NEW FILL SCALE QUIT Viewport 1 Viewport 2 Viewport 3 Viewport 0

Figure 5-3

In GKS, this is decided by associating a viewport input priority with each transformation. If the input locator position lies within more than one viewport, the viewport with the highest viewport input priority is selected to perform the transformation back to world coordinates.

MAX 4 3 2 1 0

Figure 5-4

The viewport input priorities are initially set up as in Figure 5-4, where MAX is the maximum transformation number. As can be seen, normalization transformation 0 has the highest viewport input priority initially so that all locator inputs are returned in NDC coordinates until the viewport input priority is changed (thus our examples so far have not been strictly correct). To change the viewport input priorities, the following GKS function is provided:

SET VIEWPORT INPUT PRIORITY(TR1, TR2, HILO)

This defines the viewport input priority of transformation TR1 to be higher or lower than TR2 depending on the value of the parameter HILO. For example:

      SET VIEWPORT INPUT PRIORITY(T1, T2, HIGHER)

moves transformation T1 to have a priority immediately above T2 (see Figure 5-5).

Similarly:

      SET VIEWPORT INPUT PRIORITY(T1, T2, LOWER)

moves transformation T1 to have a priority immediately below T2 (see Figure 5-6). This method of associating viewport input priorities ensures that no two transformations have the same viewport input priority.

In our original example in Section 5.3, to ensure that the coordinate position giving the new position of the duck is returned in the coordinates of normalization transformation 1 rather than 0, we should have called:

T2 T1

Figure 5-5

T1 T2

Figure 5-6
      SET VIEWPORT INPUT PRIORITY(1, 0, HIGHER)

before entering the loop to input (X, Y) coordinate values. In the example in Figure 5-3, if the MOVE operation requires the (X, Y) position in the detailed drawing (normalization transformation 2) to take precedence over the main picture (normalization transformation 1), we would need to call:

      SET VIEWPORT INPUT PRIORITY(2, 1, HIGHER)

Before either of these normalization transformations (or normalization transformation 3 for the menu) could be used, we would need to move all three viewports in front of viewport 0. This could be done by calling:

      SET VIEWPORT INPUT PRIORITY(0, 3, LOWER)

This would leave the priority ordering as in Figure 5-7.

Figure 5-8, illustrates for this example, the different normalization transformations used to return locator values depending on which viewport the input is in and on the viewport input priorities derived above. In the first situation, the locator position would be returned in the world coordinates associated with normalization transformation 1 (the main picture) whereas, in the second situation, the position would be returned in the world coordinates associated with normalization transformation 2 (the detailed drawing). In the third situation, a position in the world coordinates associated with normalization transformation 3 would be returned. The lower right hand corner does not have a user specified normalization transformation associated with it and so, in the fourth situation, the locator position would be returned in world coordinates equivalent to normalized device coordinates (normalization transformation 0).

5.4 PICK

The PICK logical input device returns the name of a segment to the application program identifying the object that has been indicated by the pick device. The program can initiate this in REQUEST mode by calling the GKS function:

MAX 4 0 3 1 2

Figure 5-7

MOVE NEW FILL SCALE QUIT MOVE NEW FILL SCALE QUIT MOVE NEW FILL SCALE QUIT MOVE NEW FILL SCALE QUIT

Figure 5-8
REQUEST PICK(WS, DV, ST, SEG, PICKID)

The REQUEST PICK function returns the name of a segment, SEG, and a more specific identification within the segment by PICKID. We shall leave the discussion of the PICKID parameter until later in this section.

Figure 5-9 shows a picture composed of a duck and tree which could have been produced by the program:

      LANDSCAPE 
      POND
      CREATE SEGMENT(1) 
      TREE 
      CLOSE SEGMENT
      CREATE SEGMENT(2) 
      DUCK 
      CLOSE SEGMENT

Consider the case where an operator wishes to perform an operation on one or other of the two objects in the picture. The program invites the operator to select which object by:

Segment 1 Segment 2

Figure 5-9
      REQUEST PICK(WS, DV, ST, SEG, PICKID)

If SEG was set to 1 by the REQUEST PICK function, the tree has been picked by the operator and, if set to 2, the duck has been picked. To move either the duck or tree to a new position in NDC space, we could define the program:

 100   CONTINUE 
      REQUEST PICK(WS, DV1, ST1, SEG, PICKID) 
      REQUEST LOCATOR(WS, DV2, ST2, NT, X, Y) 
      EVALUATE TRANSFORMATION MATRIX(0, 0, X, Y, 0, 1, 1, NDC, MAT) 
      SET SEGMENT TRANSFORMATION(SEG, MAT) 
      GOTO 100

The PICK input defines which object is to be moved. The REQUEST LOCATOR function returns a position in NDC coordinates as the viewport input priority has not been reset. The EVALUATE TRANSFORMATION MATRIX function defines the move to be applied to the segment by the SET SEGMENT TRANSFORMATION function. Note that it is the point (0,0) in NDC of each segment in the initial situation that is moved to the new position.

5.4.1 Pick Identifier

The PICKID parameter returned by REQUEST PICK identifies the operator's action more closely within the segment.

Suppose we have a diagram of a circuit board on the screen (see Figure 5-10).

To allow a particular connection to be identified, we could store each connection in a separate segment:

      DO 100 J= 1,JMAX 
      CREATE SEGMENT(J) 
      DRAW CONNECTlON(J) 
      CLOSE SEGMENT 
 100  CONTINUE

where DRAW CONNECTION is a subroutine to draw the Jth connection. Then, by calling:

      REQUEST PICK(WS, DV, ST, SEG, PICKID)

the number of the connection picked would be returned in SEG. However, for a typical circuit board, this would be a lot of segments and our local GKS may have only limited space for storing segments. An alternative is to use the pick identifier to give us a second level of naming. The pick identifier is specified by the function:

SET PICK IDENTIFIER(N)

Subsequent output primitives will have a pick identifier value of N associated with them until another call of SET PICK IDENTIFIER. For example:

Using pick identifier to identify one of many connections

Figure 5-10
      CREATE SEGMENT(1) 
      DO 100 J= 1,JMAX 
      SET PICK IDENTIFIER(J) 
      DRAW CONNECTION(J) 
 100  CONTINUE 
      CLOSE SEGMENT

Each connection has a different pick identifier associated with it, so that if we call:

      REQUEST PICK(WS, DV, ST, SEG, PICKID)

on return, SEG would contain a value of 1 indicating that one of the connecting wires, in segment 1, had been hit and the value of PICKID would indicate which one,

5.4.2 Segment Detectability

In Section 4,3, some segment attributes were described which affect the appearance of segments, There is a further segment attribute, segment detectability, which affects which segment is returned as a pick value. Segment detectability is set by the function:

SET DETECTABILITY(ID, DET)

where DET is the desired detectability and may take the values DETECTABLE and UNDETECTABLE. A segment may only be picked if it is detectable (that is, its detectability attribute has the value DETECTABLE). Since the default value is UNDETECTABLE, our examples so far have not been strictly correct as the detectability attribute for each segment should have been set to DETECTABLE. Thus, our example in Section 5.4, where we were moving the duck or tree, should have been preceded by:

      SET DETECTABILITY(1, DETECTABLE) 
      SET DETECTABILITY(2, DETECTABLE)

to allow the duck and tree to be picked. If, subsequently, the call:

      SET DETECTABILITY(2, UNDETECTABLE)

was obeyed, then segment 2 containing the duck would be made undetectable, in which case only the tree could be picked and moved. The duck could be made detectable again by resetting its detectability to DETECTABLE. Making a segment undetectable has no effect on its appearance.

However, if a segment is invisible, it is also impossible to pick it. This reflects the behaviour of a physical device like a lightpen which can only see images that are visible. It is also reasonable that the only objects that can be picked, should be those that the operator can see.

5.5 CHOICE

The CHOICE logical input device returns an integer to the application program defining which of a number of possibilities has been chosen. The program can initiate this in REQUEST mode by calling the GKS function:

REQUEST CHOICE(WS, DV, ST, CH)

where CH returns the integer representing the choice. Figures 5-3 and 5-8 show examples where one of a set of actions has been chosen by displaying a set of words in a column and using a locator input to specify which of the words has been chosen to define the next operation. Although we have used locator input so far for this purpose, it would be more usual for this to be done using a CHOICE logical input device, particularly if the display in use had a lightpen associated with it. The actual realization of the CHOICE device on a physical device can vary quite significantly, from a menu hit by a lightpen, to a set of buttons to be pushed, to a name to be typed at a keyboard.

The example in Section 5.3.2 (Figure 5-3) could have consisted of two viewports 1 and 2 containing the main picture and the detailed view. A CHOICE device could have been defined which displayed the options on the right side of the screen. To decide the next action would require:

 50   CONTINUE 
      REQUEST CHOICE(WS, DV, ST, CH) 
      GOTO(l00, 200, 300, 400, 500), CH
 100  MOVE OBJECT 
      GOTO 50
 200  DEFINE NEW OBJECT 
      GOTO 50
 300  FILL OBJECT 
      GOTO 50
 400  SCALE OBJECT 
      GOTO 50
 500  STOP

The exact method of specifying the options will be described fully in Chapter 9. Here, the subroutines, such as MOVE OBJECT, specify the action to be performed in each case.

5.6 VALUATOR

The VALUATOR logical input device returns a real value to the application program. The program can initiate this in REQUEST mode by calling the GKS function:

REQUEST VALUATOR(WS, DV, ST, VAL)

where VAL returns the real number that was input.

Clearly a single number could be input digit by digit from a keyboard without using a graphics system. However, if an interactive graphics system is in use, the operator can review the effect of a given input value without delay. If the operator does not know in advance what the best value is, then several values must be input, with the operator reviewing each in turn until the best value is obtained. If each successive value has to be input from a keyboard, the interactive dialogue is less likely to achieve an optimum value.

By contrast, REQUEST VALUATOR reads from whatever physical input hardware has been provided by a particular installation. Devices like dials can continuously provide values and graphical echoes can therefore always be up to date.

As an illustration of valuator input, we return to our flat footed friend and attempt to vary his size by valuator input. The program calls REQUEST VALUATOR, which in this instance displays a scale; the scale has marks for a minimum and a maximum and a movable current value. The movable current value is the echo for the operator input and provides an up to date indication of the current valuator value. Whenever the operator completes the input (possibly by pressing a button with the dial), the valuator value is used by our program to update the size of the duck. This continues repeatedly.

The program is as follows:

 100  CONTINUE 
      REQUEST VALUATOR(WS, DV, ST, SIZE) 
      EVALUATE TRANSFORMATION MATRIX(FX, FY, 0, 0, 0, SIZE, SIZE, WC, MAT) 
      SET SEGMENT TRANSFORMATION(DUCK, MAT) 
      GOTO 100

It is assumed that scaling is about a fixed point (FX, FY) and DUCK is the name of the segment containing the drawing of the duck. A possible interaction sequence resulting from this program is shown in Figure 5-11. The movement of the scale is as continuous as the underlying computing system and graphics hardware allows. The duck only changes size when the operator terminates each request.

1 2 3 4 5 6

Figure 5-11

In Figure 5-11, there are six snapshots. In the first, the program has drawn the duck at a standard size. In the second, REQUEST VALUATOR is called which displays as an echo the scale on the right of the screen with the initial value marked. In the third snapshot, the operator changes the valuator to a new position (lower) on the scale. Note that the duck has not changed yet because REQUEST VALUATOR has not terminated yet. In the fourth snapshot, the operator terminates the request, the program regains control and the duck now changes size. The last two snapshots show another call to REQUEST VALUATOR, with a larger value being selected in the first and the resulting change in the size of the duck, once the REQUEST VALUATOR has been completed, in the second.

The interaction could be improved if the duck was able to change size without the operator needing to press a button repeatedly. This can be achieved with SAMPLE input which is described in Chapter 6.

5.7 STRING

The STRING logical input device returns a character string to the application program. In most cases the string is echoed character by character somewhere on the display. Later (in Chapter 9), a means of controlling the position of the echo will be described. The program can initiate string input in REQUEST mode by calling the GKS function:

REQUEST STRING(WS, DV, ST, NCHARS, STR)

where STR returns the character string that was input and NCHARS returns the number of characters it contains.

String input is most often used for unknown text strings like choosing a filename or inputting a title. Selecting from a small number of strings already known to the application program, for example by using a menu, is actually closer to choice input and this usage is described later in Section 9.3.4.

STROKE

The last logical input device to be described, STROKE, returns a sequence of points to the application program, rather like a multiple locator. The program can initiate this in REQUEST mode by calling the GKS function:

REQUEST STROKE(WS, DV, PTSMAX, ST, NT, NPTS, X, Y)

An additional input parameter to the function is PTSMAX which specifies the maximum number of points that can be input by the STROKE device and effectively defines the storage available in the arrays X and Y. The STROKE input returns a sequence of positions in the arrays X and Y, from position 1 to position NPTS, and the normalization transformation NT used to transform the points back to world coordinates.

All points are transformed back using the same normalization transformation and lie within the window of that transformation. Viewport input priority is used to arbitrate between overlapping viewports in a way similar to locator input.

In Figure 5-12, if A, B, and C are three strokes input by the operator, stroke A (the pond) would be returned in viewport 1; stroke B (an enlarged view of the duck's beak) in viewport 2; and stroke C in viewport 0. (Only viewport 0 contains the whole of stroke C and so it is used to transform the stroke back to world coordinates.)

1 0 2 A B C

Figure 5-12

If echoing is on, GKS echoes the individual points of the stroke as they are input. The echo, like the echoes of other logical input values, is intended to be ephemeral, disappearing when the input is complete, where possible on the selected hardware.

When the input is over, the points delivered by REQUEST STROKE can be redisplayed using POLYLINE:

      REQUEST STROKE(WS, DV, PTSMAX, ST, NT, NPTS, X, Y) 
      SELECT NORMALIZATION TRANSFORMATION(NT) 
      POLYLINE(NPTS, X, Y)

The particular implementation of STROKE input may provide a means of sieving out unwanted points. For instance, a particular implementation of STROKE may only select points occurring at selected time intervals. The idea in this case is to capture the data describing the motion of the operator's input, not just the points passed through. This is useful in animation and signature recognition, but is impossible to achieve if the individual points are input with REQUEST LOCATOR.

5.9 A FULLER EXAMPLE OF REQUEST INPUT

This section consists of a single example which illustrates most of the logical input devices described in the chapter. It is part of an interactive program which allows the operator to control the drawing of a curve. Initially the operator inputs the points using a STROKE device. When that is done, the operator has the choice of changing the tension (tightness of fit) in the curve, selecting and moving the points, or finishing. Changing the tension is controlled by the real value returned by a VALUATOR device. In this case, it is not necessary to draw the points again, only the curve. To change the position of one of the points, it is necessary to pick one of them and then use the LOCATOR device to move it. In this case both the points and the curve are redrawn.

      TENSION = INITVALUE
      REQUEST STROKE(WS, DVS, PTSMAX, ST, NT, NP, X, Y)
 10   CREATE SEGMENT(1) 
      SET DETECTABILITY(1, DETECTABLE) 
      DO 20 KEY = 1,NP 
      SET PICK IDENTIFIER(KEY) 
      POLYMARKER(1, X(KEY), Y(KEY)) 
 20   CONTINUE 
      CLOSE SEGMENT
 30   CREATE SEGMENT(2) 
      CURVE(TENSION, NP, X, Y) 
      CLOSE SEGMENT
      REQUEST CHOICE(WS, DVC, ST, NCH) 
      GOTO(100, 200, 300), NCB
 100  REQUEST VALUATOR(WS, DVV, ST, TENSION) 
      DELETE SEGMENT(2) 
      GOTO 30
 200  REQUEST PICK(WS, DVP, ST, SEG, PKID) 
      REQUEST LOCATOR(WS, DVL, ST, NT, X(PKID), Y(PKID)) 
      DELETE SEGMENT(1) 
      DELETE SEGMENT(2) 
      GOTO 10
 300  CONTINUE
⇑ Top of page
© Chilton Computing and UKRI Science and Technology Facilities Council webmaster@chilton-computing.org.uk
Our thanks to UKRI Science and Technology Facilities Council for hosting this site