diff options
Diffstat (limited to 'ast/grf3d_pgplot.c')
-rw-r--r-- | ast/grf3d_pgplot.c | 3414 |
1 files changed, 3414 insertions, 0 deletions
diff --git a/ast/grf3d_pgplot.c b/ast/grf3d_pgplot.c new file mode 100644 index 0000000..3a249e2 --- /dev/null +++ b/ast/grf3d_pgplot.c @@ -0,0 +1,3414 @@ +/* +* Name: +* grf3d_pgplot.c + +* Purpose: +* Implement the grf3d interface using the PGPLOT graphics system. + +* Description: +* This file implements the low level 3D graphics functions required +* by the rest of AST, by calling suitable PGPLOT functions (the +* FORTRAN PGPLOT interface is used). +* +* This file can be used as a template for the development of +* similar implementations based on other graphics systems. +* +* Unlike world coordinates used by the 2D grf interface, the 3D world +* coordinates used by the grf3D interface are assume to be equally scaled +* (that is, they are assumed to have the same units). Therefore this +* module has no equivalent to the astGScales function defined by the +* 2D grf interface. + +* Copyright: +* Copyright (C) 2007 Science & Technology Facilities Council. +* All Rights Reserved. + +* Licence: +* This program is free software: you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* License along with this program. If not, see +* <http://www.gnu.org/licenses/>. + +* Authors: +* DSB: David S. Berry (Starlink) + +* History: +* 20-JUN-2007 (DSB): +* Original version. +*/ + + +/* Macros */ +/* ====== */ +#define MXDEV 16 /* Max no of concurrent PGPLOT devices */ +#define MXSTRLEN 80 /* Max PGPLOT string length */ +#define CAMERA_OK 123456789 /* Flags that a Camera has been initialised */ +#define TWOPI 6.28318530718 /* 2*PI */ +#define MXSIDE 32 /* Max no of sides in a marker polygon */ + + +/* Header files. */ +/* ============= */ +/* AST header files */ +#include "grf3d.h" /* The grf3D interface definition */ +#include "pg3d.h" /* Other public functions in this module */ +#include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ +#include "c2f77.h" /* C to FORTRAN interface functions */ +#include "memory.h" /* Memory allocation facilities */ +#include "error.h" /* Error reporting facilities */ +#include "pointset.h" /* Defines AST__BAD */ +#include "ast_err.h" /* AST error codes */ + +/* System header files */ +#include <string.h> +#include <math.h> +#include <float.h> +#include <limits.h> +#include <stdio.h> + + +/* Type definitions. */ +/* ================= */ +/* Structure defining the position and orientation of the camera in 3D + world coords. This is specific to the PGPLOT implementation. Other + implementations need not include any equivalent to this structure. */ +typedef struct camera { + float eye_vector[3]; + float target_vector[3]; + float up_vector[3]; + float w2c_matrix[9]; + float screen_distance; + int ok_flag; +} Camera; + + +/* Module variables. */ +/* ================= */ +/* One camera structure for each PGPLOT device identifier. PGPLOT allows + a maximum of 8 concurrent devices at the moment. Make the array twice + this size to allow for some future expansion in PGPLOT. Again, this is + specific to the PGPLOT implementation of the grf3D interface. */ +static Camera cameras[ MXDEV ]; + +/* Function templates. */ +/* =================== */ +/* Templates for functions that are private to this module. */ +static Camera *getCamera( int ); +static float getCharHeight( void ); +static int Polygon( int, float *, float *, float *, float[3], float[3], float[3], float[3] ); +static int Text( int *, int, float[3], const char *, float[3], float[3], float[3] ); +static int TextCam( Camera *, float[3], float[3], float[3], float[3] ); +static int TxExt( int *, int, float[3], const char *, float[3], float[3], float[3], float *, float *, float *, float[3] ); +static int getTextAxes( float[3], float[3], float[3], const char *, float[3], float[3], float[3], char[3] ); +static int transform( Camera *, int, float *, float *, float *, float *, float * ); +static int vectorNorm( float * ); +static float vectorModulus( float * ); +static void getSymbolList( const char *, int, int *, int * ); +static void vectorProduct( float *, float *, float * ); +static float dotProduct( float *, float * ); +static void vectorSub( float *, float *, float * ); + +/* Templates for private functions that wrap PGPLOT Fortran routines. */ +static void ccgrsyds( int *, int *, const char *, int, int ); +static void ccgrsymk( int, int, int * ); +static void ccgrsyxd( int, int *, int * ); +static void ccpgline( int, float[], float[] ); +static void ccpgpoly( int, float[], float[] ); +static void ccpgqcf( int * ); +static void ccpgqcf(int *); +static void ccpgqch( float * ); +static void ccpgqci( int * ); +static void ccpgqclp( int * ); +static void ccpgqid( int * ); +static void ccpgqls( int * ); +static void ccpgqlw( int * ); +static void ccpgqvsz( int, float *, float *, float *, float * ); +static void ccpgqwin( float *, float *, float *, float * ); +static void ccpgscf( int ); +static void ccpgsch( float ); +static void ccpgsci( int ); +static void ccpgsclp( int ); +static void ccpgsls( int ); +static void ccpgslw( int ); +static void ccpgswin( float, float, float, float ); +static void ccpgupdt( void ); + + +/* Templates for Fortran PGPLOT routines needed by this module. */ +F77_SUBROUTINE(grsyds)( INTEGER_ARRAY(list), INTEGER(nlist), CHARACTER(text), INTEGER(font) TRAIL(text) ); +F77_SUBROUTINE(grsymk)( INTEGER(type), INTEGER(font), INTEGER(symbol) ); +F77_SUBROUTINE(grsyxd)( INTEGER(symbol), INTEGER_ARRAY(xygrid), INTEGER(unused) ); +F77_SUBROUTINE(pgline)( INTEGER(N), REAL_ARRAY(X), REAL_ARRAY(Y) ); +F77_SUBROUTINE(pgpoly)( INTEGER(N), REAL_ARRAY(X), REAL_ARRAY(Y) ); +F77_SUBROUTINE(pgqcf)( INTEGER(ival) ); +F77_SUBROUTINE(pgqch)( REAL(rval) ); +F77_SUBROUTINE(pgqci)( INTEGER(ival) ); +F77_SUBROUTINE(pgqclp)( INTEGER(clip) ); +F77_SUBROUTINE(pgqid)( INTEGER(id) ); +F77_SUBROUTINE(pgqls)( INTEGER(ival) ); +F77_SUBROUTINE(pgqlw)( INTEGER(ival) ); +F77_SUBROUTINE(pgqvsz)( INTEGER(units), REAL(x1), REAL(x2), REAL(y1), REAL(y2) ); +F77_SUBROUTINE(pgqwin)( REAL(wx1), REAL(wx2), REAL(wy1), REAL(wy2) ); +F77_SUBROUTINE(pgscf)( INTEGER(ival) ); +F77_SUBROUTINE(pgsch)( REAL(rval) ); +F77_SUBROUTINE(pgsci)( INTEGER(ival) ); +F77_SUBROUTINE(pgsclp)( INTEGER(clip) ); +F77_SUBROUTINE(pgsls)( INTEGER(ival) ); +F77_SUBROUTINE(pgslw)( INTEGER(ival) ); +F77_SUBROUTINE(pgswin)( REAL(X1), REAL(X2), REAL(Y1), REAL(Y2) ); +F77_SUBROUTINE(pgupdt)( void ); + + +/* Public functions defined by the grf3D interface. */ +/* ================================================ */ +/* All implementations of the grf3d interface must provide implementations + of all the functions in this block. The corresponding templates are in + grf3d.h */ + + +int astG3DAttr( int attr, double value, double *old_value, int prim ){ +/* +*+ +* Name: +* astG3DAttr + +* Purpose: +* Enquire or set a 3D graphics attribute value. + +* Synopsis: +* #include "grf3d.h" +* int int astG3DAttr( int attr, double value, double *old_value, int prim ) + +* Description: +* This function returns the current value of a specified 3D graphics +* attribute, and optionally establishes a new value. The supplied +* value is converted to an integer value if necessary before use. + +* Parameters: +* attr +* An integer value identifying the required attribute. The +* following symbolic values are defined in grf3d.h: +* +* GRF__STYLE - Line style. +* GRF__WIDTH - Line width. +* GRF__SIZE - Character and marker size scale factor. +* GRF__FONT - Character font. +* GRF__COLOUR - Colour index. +* value +* A new value to store for the attribute. If this is AST__BAD +* no value is stored. +* old_value +* A pointer to a double in which to return the attribute value. +* If this is NULL, no value is returned. +* prim +* The sort of graphics primitive to be drawn with the new attribute. +* Identified by the following values defined in grf.h: +* GRF__LINE +* GRF__MARK +* GRF__TEXT + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: + +*- +*/ + + int ival; + float rval, dx, dy, deflw, x1, x2, y1, y2; + +/* If required retrieve the current line style, and set a new line style. */ + if( attr == GRF__STYLE ){ + ccpgqls( &ival ); + if( old_value ) *old_value = (double) ival; + + if( value != AST__BAD ){ + ival = (int) ( value + 0.5 ); + if( value < 0.0 ) ival -= 1; + + ival = ( ival - 1 ) % 5; + ival += ( ival < 0 ) ? 6 : 1; + + ccpgsls( ival ); + } + +/* If required retrieve the current line width, and set a new line width. + Line width is stored in Plot as a scale factor (1.0 for the default line + width which is a fixed fraction of the diagonal of the view surface), but + pgplot stores it in units of 0.005 of an inch. */ + } else if( attr == GRF__WIDTH ){ + +/* Get the bounds of the view surface in inches. */ + ccpgqvsz( 1, &x1, &x2, &y1, &y2 ); + +/* Find the default line width in inches (i.e. 0.0005 of the length + of the view surface diagonal). */ + dx = ( x1 - x2 ); + dy = ( y1 - y2 ); + deflw = 0.0005*sqrt( (double )( dx*dx + dy*dy ) ); + +/* Get the current pgplot line width in units of 0.005 of an inch. */ + ccpgqlw( &ival ); + +/* If required, return the factor by which this exceeds the default line + width found above. */ + if( old_value ) *old_value = (double)( ival )/( 200.0 * deflw ); + +/* If a new line width has been provided, the pgplot line width needs to + be set to the corresponding absolute value. */ + if( value != AST__BAD ){ + ival = (int) ( 200.0*value*deflw ); + if( ival < 1 ) { + ival = 1; + } else if( ival > 201 ){ + ival = 201; + } + ccpgslw( ival ); + } + +/* If required retrieve the current character size, and set a new size. + The attribute value should be a factor by which to multiply the + default character size. */ + } else if( attr == GRF__SIZE ){ + ccpgqch( &rval ); + if( old_value ) *old_value = (double) rval; + + if( value != AST__BAD ){ + ccpgsch( (float) value ); + } + +/* If required retrieve the current character font, and set a new font. */ + } else if( attr == GRF__FONT ){ + ccpgqcf( &ival ); + if( old_value ) *old_value = (double) ival; + + if( value != AST__BAD ){ + ival = (int) ( value + 0.5 ); + if( value < 0.0 ) ival -= 1; + + ival = ( ival - 1 ) % 4; + ival += ( ival < 0 ) ? 5 : 1; + ccpgscf( ival ); + } + +/* If required retrieve the current colour index, and set a new colour + index. */ + } else if( attr == GRF__COLOUR ){ + ccpgqci( &ival ); + if( old_value ) *old_value = (double) ival; + + if( value != AST__BAD ){ + ival = (int) ( value + 0.5 ); + if( ival < 0 ) ival = 1; + ccpgsci( ival ); + } + +/* Give an error message for any other attribute value. */ + } else { + astError( AST__GRFER, "astG3DAttr: Unknown graphics attribute '%d' " + "requested.", attr ); + return 0; + } + +/* Return. */ + return 1; +} + +int astG3DCap( int cap, int value ){ +/* +*+ +* Name: +* astG3DCap + +* Purpose: +* Indicate if this grf3d module has a given capability. + +* Synopsis: +* #include "grf3d.h" +* int astG3DCap( int cap, int value ) + +* Description: +* This function is called by the AST Plot class to determine if the +* grf3d module has a given capability, as indicated by the "cap" +* argument. + +* Parameters: +* cap +* The capability being inquired about. This will be one of the +* following constants defined in grf3d.h: +* +* GRF3D__ESC: This function should return a non-zero value if the +* astG3DText and astG3DTxExt functions can recognise and interpret +* graphics escape sequences within the supplied string. These +* escape sequences are described below. Zero should be returned +* if escape sequences cannot be interpreted (in which case the +* Plot class will interpret them itself if needed). The supplied +* "value" argument should be ignored only if escape sequences cannot +* be interpreted by astG3DText and astG3DTxExt. Otherwise, "value" +* indicates whether astG3DText and astG3DTxExt should interpret escape +* sequences in subsequent calls. If "value" is non-zero then +* escape sequences should be interpreted by astG3DText and +* astG3DTxExt. Otherwise, they should be drawn as literal text. + +* Returned Value: +* The return value, as described above. Zero should be returned if +* the supplied capability is not recognised. + +* Escape Sequences: +* Escape sequences are introduced into the text string by a percent +* "%" character. The following escape sequences are currently recognised +* ("..." represents a string of one or more decimal digits): +* +* %% - Print a literal "%" character (type GRF__ESPER ). +* +* %^...+ - Draw subsequent characters as super-scripts. The digits +* "..." give the distance from the base-line of "normal" +* text to the base-line of the super-script text, scaled +* so that a value of "100" corresponds to the height of +* "normal" text (type GRF__ESSUP ). +* %^+ - Draw subsequent characters with the normal base-line. +* +* %v...+ - Draw subsequent characters as sub-scripts. The digits +* "..." give the distance from the base-line of "normal" +* text to the base-line of the sub-script text, scaled +* so that a value of "100" corresponds to the height of +* "normal" text (type GRF__ESSUB ). +* +* %v+ - Draw subsequent characters with the normal base-line +* (equivalent to %^+). +* +* %>...+ - Leave a gap before drawing subsequent characters. +* The digits "..." give the size of the gap, scaled +* so that a value of "100" corresponds to the height of +* "normal" text (type GRF__ESGAP ). +* +* %<...+ - Move backwards before drawing subsequent characters. +* The digits "..." give the size of the movement, scaled +* so that a value of "100" corresponds to the height of +* "normal" text (type GRF_ESBAC). +* +* %s...+ - Change the Size attribute for subsequent characters. The +* digits "..." give the new Size as a fraction of the +* "normal" Size, scaled so that a value of "100" corresponds +* to 1.0 (type GRF__ESSIZ ). +* +* %s+ - Reset the Size attribute to its "normal" value. +* +* %w...+ - Change the Width attribute for subsequent characters. The +* digits "..." give the new width as a fraction of the +* "normal" Width, scaled so that a value of "100" corresponds +* to 1.0 (type GRF__ESWID ). +* +* %w+ - Reset the Size attribute to its "normal" value. +* +* %f...+ - Change the Font attribute for subsequent characters. The +* digits "..." give the new Font value (type GRF__ESFON ). +* +* %f+ - Reset the Font attribute to its "normal" value. +* +* %c...+ - Change the Colour attribute for subsequent characters. The +* digits "..." give the new Colour value (type GRF__ESCOL ). +* +* %c+ - Reset the Colour attribute to its "normal" value. +* +* %t...+ - Change the Style attribute for subsequent characters. The +* digits "..." give the new Style value (type GRF__ESSTY ). +* +* %t+ - Reset the Style attribute to its "normal" value. +* +* %- - Push the current graphics attribute values onto the top of +* the stack - see "%+" (type GRF__ESPSH). +* +* %+ - Pop attributes values of the top the stack - see "%-". If +* the stack is empty, "normal" attribute values are restored +* (type GRF__ESPOP). +* +* The astFindEscape function (in libast.a) can be used to locate escape +* sequences within a text string. It has the following signature: +* +* #include "plot.h" +* int astFindEscape( const char *text, int *type, int *value, int *nc ) +* +* Parameters: +* text +* Pointer to the string to be checked. +* type +* Pointer to a location at which to return the type of escape +* sequence. Each type is identified by a symbolic constant defined +* in grf.h and is indicated in the above section. The returned value +* is undefined if the supplied text does not begin with an escape +* sequence. +* value +* Pointer to a lcation at which to return the integer value +* associated with the escape sequence. All usable values will be +* positive. Zero is returned if the escape sequence has no associated +* integer. A value of -1 indicates that the attribute identified by +* "type" should be reset to its "normal" value (as established using +* the astG3DAttr function, etc). The returned value is undefined if +* the supplied text does not begin with an escape sequence. +* nc +* Pointer to a location at which to return the number of +* characters read by this call. If the text starts with an escape +* sequence, the returned value will be the number of characters in +* the escape sequence. Otherwise, the returned value will be the +* number of characters prior to the first escape sequence, or the +* length of the supplied text if no escape sequence is found. + +* Returned Value: +* A non-zero value is returned if the supplied text starts with a +* graphics escape sequence, and zero is returned otherwise. + +*- +*/ + + return 0; +} + +int astG3DFlush( void ){ +/* +*+ +* Name: +* astG3DFlush + +* Purpose: +* Flush all pending graphics to the output device. + +* Synopsis: +* #include "grf3d.h" +* int astG3DFlush( void ) + +* Description: +* This function ensures that the display device is up-to-date, +* by flushing any pending graphics to the output device. + +* Parameters: +* None. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +*- +*/ + + ccpgupdt(); + return 1; +} + +int astG3DLine( int n, float *x, float *y, float *z ){ +/* +*+ +* Name: +* astG3DLine + +* Purpose: +* Draw a polyline (i.e. a set of connected lines). + +* Synopsis: +* #include "grf3d.h" +* int astG3DLine( int n, float *x, float *y, float *z ) + +* Description: +* This function displays lines joining the given positions. + +* Parameters: +* n +* The number of positions to be joined together. +* x +* A pointer to an array holding the "n" x values. +* y +* A pointer to an array holding the "n" y values. +* z +* A pointer to an array holding the "n" z values. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - A camera must have been established prior to calling this +* function using either astG3DSetCamera or astG3DAutoCamera. +* - Nothing is done if "n" is less than 2, or if a NULL pointer is +* given for either "x", "y" or "z". + +*- +*/ + +/* Local Variables: */ + int clip; + int result = 0; + float *h, *r; + +/* Do nothing if we have less than 2 points, but do not indicate an error. */ + if( n < 2 ){ + result = 1; + +/* Check the pointers. */ + } else if( x && y && z ) { + +/* Save the current clipping flag, and ensure clipping is off. */ + ccpgqclp( &clip ); + ccpgsclp( 0 ); + +/* Allocate work space for the 2D world coordinate positions. */ + h = astMalloc( sizeof( float )*(size_t) n ); + r = astMalloc( sizeof( float )*(size_t) n ); + if( astOK ) { + +/* Convert the supplied points from 3D world coordinates to 2D world + (i.e. screen) coordinates. If succesful, plot the lines. */ + if( transform( NULL, n, x, y, z, h, r ) ) { + ccpgline( n, (float *) h, (float *) r ); + result = 1; + } + } + +/* Free work space. */ + h = astFree( h ); + r = astFree( r ); + +/* Re-instate original clipping flag. */ + ccpgsclp( clip ); + + } + return result; +} + +int astG3DMark( int n, float *x, float *y, float *z, int type, + float norm[3] ){ +/* +*+ +* Name: +* astG3DMark + +* Purpose: +* Draw a set of markers. + +* Synopsis: +* #include "grf.h" +* int astG3DMark( int n, float *x, float *y, float *z, int type, +* float norm[3] ) + +* Description: +* This function draws markers centred at the given positions, on a +* plane with a specified normal vector. + +* Parameters: +* n +* The number of markers to draw. +* x +* A pointer to an array holding the "n" x values. +* y +* A pointer to an array holding the "n" y values. +* z +* A pointer to an array holding the "n" z values. +* type +* An integer which can be used to indicate the type of marker symbol +* required. See the description of routine PGPT in the PGPLOT manual. +* norm +* The (x,y,z) components of a vector that is normal to the plane +* containing the marker. The given vector passes through the marker +* from the back to the front. If all components of this vector are +* zero, then a normal vector pointing from the position of the +* first marker towards the camera eye is used. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Nothing is done if "n" is less than 1, or if a NULL pointer is +* given for "x", "y" or "z". + +*- +*/ + +/* local Variables: */ + char just[3]; + float ref[3]; + float up[3]; + float tx[3], ty[3], tz[3]; + float vx[ MXSIDE ], vy[ MXSIDE ], vz[ MXSIDE ]; + float ch, ang, dang; + int clip; + int font; + int i; + int nlist; + int symnum; + int ns; + +/* Return if any of the coordinate pointers is NULL. */ + if( !x || !y || !z ) return 1; + +/* Initialise */ + ns = 0; + +/* Unless the "norm" vector is parallel to the z axis, we use an up vector + that is parallel to the z axis. Otherwise we use an up vector paralle + to the x axis. */ + if( norm[ 0 ] != 0.0 || norm[ 1 ] != 0.0 ) { + up[ 0 ] = 0.0; + up[ 1 ] = 0.0; + up[ 2 ] = 1.0; + } else { + up[ 0 ] = 1.0; + up[ 1 ] = 0.0; + up[ 2 ] = 0.0; + } + +/* Create unit vectors along the three axes of the text plane + coordinate system. */ + ref[ 0 ] = x[ 0 ]; + ref[ 1 ] = y[ 0 ]; + ref[ 2 ] = z[ 0 ]; + if( !getTextAxes( ref, up, norm, "CC", tx, ty, tz, just ) ) return 0; + +/* Calculate the pgplot symbol number for the given marker type. */ + if( type > 0 ) { + if( type > 127 ) { + symnum = type; + } else { + ccpgqcf( &font ); + ccgrsymk( type, font, &symnum ); + } + + } else if( type > -3 ) { + getSymbolList( ".", 1, &symnum, &nlist ); + +/* Regular polygons - create an array of text plane coordinates for the + vertices of the polygon. */ + } else { + symnum = type; + +/* Get the character height in world coordinate units. A PGPLOT + character height of 1.0 corresponds to 1/40 of the 2D window height. */ + ch = getCharHeight(); + +/* Limit the number of sides that can be produced. */ + ns = -type; + if( ns > MXSIDE ) ns = MXSIDE; + +/* Calculate the angle subtended by each edge of the polygon. */ + dang = TWOPI/ns; + ang = 0.0; + +/* Loop round each vertex. */ + for( i = 0; i < ns; i++ ) { + vx[ i ] = ch*sin( ang ); + vy[ i ] = ch*cos( ang ); + vz[ i ] = 0.0; + ang += dang; + } + } + +/* Save the current clipping flag, and ensure clipping is off. */ + ccpgqclp( &clip ); + ccpgsclp( 0 ); + +/* Draw each marker in turn. */ + for( i = 0; i < n; i++ ) { + +/* Store the centre world coords */ + ref[ 0 ] = x[ i ]; + ref[ 1 ] = y[ i ]; + ref[ 2 ] = z[ i ]; + +/* Draw the symbol, and return if anything goes wrong. */ + if( symnum >= 0 ) { + if( !Text( &symnum, 1, ref, "CC", tx, ty, tz ) ) return 0; + + } else { + if( !Polygon( ns, vx, vy, vz, ref, tx, ty, tz ) ) return 0; + + } + + } + +/* Re-instate original clipping flag. */ + ccpgsclp( clip ); + +/* If we arrive here we have been succesful, so return a non-zero value. */ + return 1; +} + +int astG3DQch( float *ch ){ +/* +*+ +* Name: +* astG3DQch + +* Purpose: +* Return the character height in world coordinates. + +* Synopsis: +* #include "grf3d.h" +* int astG3DQch( float *ch ) + +* Description: +* This function returns the height of characters drawn using astG3DText. + +* Parameters: +* ch +* A pointer to the double which is to receive the height of +* characters drawn with astG3DText. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Since the 3D world coordinate axes are assumed to be equally +* scaled, the height of text in world coordinate units is independent +* of the orientation of the text. Therefore, this function returns +* only one height value, unlike the equivalent 2D astGQch function +* that returns two heights. +*- +*/ + *ch = getCharHeight(); + return 1; +} + +int astG3DText( const char *text, float ref[3], const char *just, float up[3], + float norm[3] ){ +/* +*+ +* Name: +* astG3DText + +* Purpose: +* Draw a character string. + +* Synopsis: +* #include "grf3d.h" +* int astG3DText( const char *text, float ref[3], const char *just, +* float up[3], float norm[3] ) + +* Description: +* This function displays a character string at a given position +* on a given plane in 3D world coords, using a specified +* justification and up-vector. + +* Parameters: +* text +* Pointer to a null-terminated character string to be displayed. +* ref +* The reference (x,y,z) coordinates. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* up +* The (x,y,z) up-vector for the text. The actual up vector used is +* the projection of the supplied vector onto the plane specified by +* "norm". +* norm +* The (x,y,z) components of a vector that is normal to the plane +* containing the text. The given vector passes through the text +* from the back to the front. If all components of this vector are +* zero, then a normal vector pointing towards the camera eye is used. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - This routine does not recognise PGPLOT escape sequences. +* - A NULL value for "just" causes a value of "CC" to be used. +*- +*/ + +/* Local Constants: */ +#define MXLEN 256 + +/* Local Variables: */ + char newjust[3]; + float tx[3], ty[3], tz[3]; + int list[ MXLEN ]; + int nlist; + +/* Convert the supplied string into a list of PGPLOT symbol numbers */ + getSymbolList( text, MXLEN, &nlist, list ); + +/* Create unit vectors along the three axes of the text plane + coordinate system. */ + if( !getTextAxes( ref, up, norm, just, tx, ty, tz, newjust ) ) return 0; + +/* Draw the text. */ + return Text( list, nlist, ref, newjust, tx, ty, tz ); + +/* Clear local constants. */ +#undef MXLEN +} + +int astG3DTxExt( const char *text, float ref[3], const char *just, + float up[3], float norm[3], float *xb, float *yb, + float *zb, float bl[3] ){ +/* +*+ +* Name: +* astG3DTxExt + +* Purpose: +* Get the extent of a character string. + +* Synopsis: +* #include "grf3d.h" +* int astG3DTxExt( const char *text, float ref[3], const char *just, +* float up[3], float norm[3], float *xb, float *yb, +* float *zb, float bl[3] ) + +* Description: +* This function returns the corners of a box which would enclose the +* supplied character string if it were displayed using astG3DText. +* +* The returned box INCLUDES any leading or trailing spaces. + +* Parameters: +* text +* Pointer to a null-terminated character string to be displayed. +* ref +* The reference (x,y,z) coordinates. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", 'B' for "baseline", or "M" for "bottom", and +* specifies the vertical location of the reference position. Note, +* "baseline" corresponds to the base-line of normal text. Some +* characters (eg "y", "g", "p", etc) descend below the base-line, +* and so "M" and "B" will produce different effects for such +* characters. The second character may be 'L' for "left", 'C' for +* "centre", or 'R' for "right", and specifies the horizontal +* location of the reference position. If the string has less than +* 2 characters then 'C' is used for the missing characters. +* up +* The (x,y,z) up-vector for the text. The actual up vector used is +* the projection of the supplied vector onto the plane specified by +* "norm". +* norm +* The (x,y,z) components of a vector that is normal to the plane +* containing the text. The given vector passes through the text +* from the back to the front. If all components of this vector are +* zero, then a normal vector pointing towards the camera eye is used. +* xb +* An array of 4 elements in which to return the x coordinate of +* each corner of the bounding box. +* yb +* An array of 4 elements in which to return the y coordinate of +* each corner of the bounding box. +* zb +* An array of 4 elements in which to return the z coordinate of +* each corner of the bounding box. +* bl +* The 3D world coordinates at the left hand end of the text +* baseline. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - The order of the corners is anti-clockwise starting at the +* bottom left when viewing the text normally (i.e. face on). +* - This routine does not recognise PGPLOT escape sequences. +* - A NULL value for "just" causes a value of "CC" to be used. +*- +*/ + +/* Local Constants: */ +#define MXLEN 256 + +/* Local Variables: */ + char newjust[3]; + int i; + int list[ MXLEN ]; + int nlist; + float tx[3], ty[3], tz[3]; + +/* Initialise the returned values to indicate no box available. */ + for( i = 0; i < 4; i++ ){ + xb[ i ] = 0.0; + yb[ i ] = 0.0; + zb[ i ] = 0.0; + } + +/* Convert the supplied string into a list of symbol numbers */ + getSymbolList( text, MXLEN, &nlist, list ); + +/* Create unit vectors along the three axes of the text plane + coordinate system. */ + if( !getTextAxes( ref, up, norm, just, tx, ty, tz, newjust ) ) return 0; + +/* Find the bounding box of this list of symbols. */ + return TxExt( list, nlist, ref, newjust, tx, ty, tz, xb, yb, zb, bl ); + +/* Clear local constants. */ +#undef MXLEN +} + + +/* Public functions specific to this PGPLOT implementation. */ +/* ======================================================== */ +/* Other implementations of the grf3d interface can ignore the following + functions. They provide control of the 3D view. */ + +int PG3DSetCamera( float eye[3], float target[3], float up[3], float screen ){ +/* +*+ +* Name: +* PG3DSetCamera + +* Purpose: +* Store new camera settings for the current PGPLOT device. + +* Synopsis: +* #include "grf3d.h" +* int PG3DSetCamera( float eye[3], float target[3], float up[3], +* float screen ) + +* Description: +* This function stores new camera settings for the current PGPLOT +* device. +* +* A "camera" describes the projection of the 3D world coordinate +* space onto a 2D "screen". This screen corresponds to the 2D viewing +* surface used by PGPLOT. The 2D window used by PGPLOT (as set by +* PGSWIN, etc) defines the bounds of the screen area that is visible +* in the PGPLOT viewport. +* +* The 3D world coordinate axes (x,y,z) are such that if "z" is +* vertically upwards and "x" points to the right, then "y" goes +* out of the paper away from you. All 3 axes are assume to have equal +* scale. +* +* A camera defines a second set of 3D axes (called "(u,v,w)") with +* origin at the 3D world coordinates given by "eye": +* +* - the "w" axis points towards the position given by "target" +* - the "v" axis is perpendicular to the "w" axis and is in the plane +* spanned by the "w" axis and the supplied "up" vector +* - the "u" axis is perpendicular to both "w" and "v" and points to +* the left when looking from the eye along the w axis with the v +* axis upwards +* +* Thus the "v" axis is parallel to "vertically up" on the 2D screen, +* "u" is parallel to "horizontally to the left", and "w" is +* perpendicular to the screen, pointing towards the target. +* +* The screen is a plane perpendicular to the "w" axis, at the "w" axis +* value given by "screen". A 2D cartesian coordinate system (h,r) is +* defined on the screen, with origin at the point where the "w" axis +* intersects the screen. The "h" (horizontal) axis is parallel to the +* "u" axis but points in the opposite direction (to the left), and the +* "r" (vertical) axis is parallel to the "v" axis. The (h,r) system is +* taken to be the same as the PGPLOT 2D world coordinate system, and +* PGSWIN can therefore be used to specify the rectangular area on the +* screen that is mapped onto the PGPLOT viewport. +* +* It is assumed that all axes (x,y,z), (u,v,w) and (h,r) are measured +* in the same units. + +* Parameters: +* eye +* The position vector of the camera's "eye", in 3D world coordinates. +* target +* The position vector of a point in 3D world coordinates that is +* at the centre of the camera's view. In other words, the camera is +* looking towards this point. Zero will be returned if the target +* is the same position as the eye. +* up +* A vector in 3D world coordinates that will appear vertically +* upwards when projected onto the screen. Zero will be returned if +* the up vector has zero length or is parallel to the line joining +* the eye and the target. +* screen +* The distance from the camera's eye to the projection screen. If +* this is zero, then an orthographic projection is used. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +*- +*/ + +/* Local Variables: */ + Camera *cam; + float *u, *v, *w; + int result = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 0 ); + if( cam ) { + result = 1; + +/* Store the supplied values in the camera. */ + memcpy( cam->target_vector, target, 3*sizeof( float ) ); + memcpy( cam->eye_vector, eye, 3*sizeof( float ) ); + cam->screen_distance = screen; + +/* Get pointers to the three rows of the w2c_matrix. This is a 3x3 matrix that + rotates vectors in the (x,y,z) system into vectors in the (u,v,w) + system. Each row in the matrix is a unit vector along the u, v or w + axes. */ + u = cam->w2c_matrix; + v = u + 3; + w = v + 3; + +/* The "w" axis points form the eye to the target, so get the vector from + the eye to the target and normalise it. */ + vectorSub( target, eye, w ); + if( ! vectorNorm( w ) ) result = 0; + +/* The "v" vector is in the plane spanned by the "w" axis and the "up" + vector. Get the normal to this plane, storing the result temporarily + in the "u" vector. . */ + vectorProduct( w, up, u ); + +/* The "v" vector is normal to the vector found above and is also normal + to the "w" axis. Get this vector and normalise it. */ + vectorProduct( u, w, v ); + if( ! vectorNorm( v ) ) result = 0; + +/* The "u" vector is perpendicualr to both the "w" and "v" vectors. */ + vectorProduct( v, w, u ); + if( ! vectorNorm( u ) ) result = 0; + +/* Use "v" as the stored up vector (the supplied "up" vector is not + necesarily the same as "v"). */ + memcpy( cam->up_vector, v, 3*sizeof( float ) ); + +/* Se a flag that indicates that the Camera is usable. */ + cam->ok_flag = result ? CAMERA_OK : CAMERA_OK/2; + } + + return result; +} + +int PG3DGetCamera( float eye[3], float target[3], float up[3], float *screen ){ +/* +*+ +* Name: +* PG3DGetCamera + +* Purpose: +* Get the current camera settings for the current PGPLOT device. + +* Synopsis: +* #include "grf3d.h" +* int PG3DGetCamera( float eye[3], float target[3], float up[3], +* float *screen ) + +* Description: +* This function retrieves the current camera settings for the current +* PGPLOT device. See PG3DSetCamera for more info. Any of the supplied +* parameters can be set to NULL if the information is not needed. + +* Parameters: +* eye +* The position vector of the camera's "eye", in 3D world coordinates. +* target +* The position vector of a point in 3D world coordinates that is +* at the centre of the camera's view. In other words, the camera is +* looking towards this point. Zero will be returned if the target +* is the same position as the eye. +* up +* A vector in 3D world coordinates that will appear vertically +* upwards when projected onto the screen. Zero will be returned if +* the up vector has zero length or is parallel to the line joining +* the eye and the target. +* screen +* The distance from the camera's eye to the projection screen. If +* this is zero, then an orthographic projection is used. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 0 ); + if( cam ) { + result = 1; + +/* Copy the current values into the supplied arrays. */ + if( target ) memcpy( target, cam->target_vector, 3*sizeof( float ) ); + if( eye) memcpy( eye, cam->eye_vector, 3*sizeof( float ) ); + if( up ) memcpy( up, cam->up_vector, 3*sizeof( float ) ); + if( screen ) *screen = cam->screen_distance; + result = ( cam->ok_flag == CAMERA_OK ); + } + + return result; +} + +int PG3DSetEye( float eye[3] ){ +/* +*+ +* Name: +* PG3DSetEye + +* Purpose: +* Store a new camera eye position for the current PGPLOT device. + +* Synopsis: +* #include "grf3d.h" +* int PG3DSetEye( float eye[3] ) + +* Description: +* This function modifies the camera eye position for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. + +* Parameters: +* eye +* The position vector of the camera's "eye", in 3D world coordinates. +* Zero is returned if the new eye position is the same as the +* existing camera target position. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + +/* If so, modify the camera values, using the supplied eye position but + retaining the other camera settings. */ + result = PG3DSetCamera( eye, cam->target_vector, cam->up_vector, + cam->screen_distance ); + } + + return result; +} + +int PG3DRotateEye( int dir, float angle ){ +/* +*+ +* Name: +* PG3DRotateEye + +* Purpose: +* Move the eye on a great circle around the current target position. + +* Synopsis: +* #include "grf3d.h" +* int PG3DRotateEye( int dir, float angle ) + +* Description: +* This function modifies the camera eye position for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. +* +* The eye is moved by a gven distance along an arc of a great circle +* centred on the current target position. The target position itself +* is left unchanged. + +* Parameters: +* dir +* The direction in which to move the eye position: +* 1 - Move eye upwards +* 2 - Move eye downwards +* 3 - Move eye left +* 4 - Move eye right +* angle +* The arc-distance, in degrees, by which to move the eye. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + int i; + float e[3], f[3], emod, neweye[3], sina, cosa; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + +/* Get the cos and sine of the supplied angle. */ + cosa = cos( angle*TWOPI/360 ); + sina = sin( angle*TWOPI/360 ); + +/* Get the vector from the target to the eye, get its modulus. */ + vectorSub( cam->eye_vector, cam->target_vector, e ); + emod = vectorModulus( e ); + +/* If we are moving the eye upwards, find the new eye position. */ + if( dir == 1 ) { + for( i = 0; i < 3; i++ ) { + neweye[ i ] = e[ i ]*cosa + emod*cam->up_vector[ i ]*sina + + cam->target_vector[ i ]; + } + +/* If we are moving the eye downwards, find the new eye position. */ + } else if( dir == 2 ) { + for( i = 0; i < 3; i++ ) { + neweye[ i ] = e[ i ]*cosa - emod*cam->up_vector[ i ]*sina + + cam->target_vector[ i ]; + } + +/* If we are moving the eye left or right we need a vector in the plane + of rotation that is at right angles to "e", and points to the right + of the eye. */ + } else { + vectorProduct( cam->up_vector, e, f ); + vectorNorm( f ); + +/* Get the new eye position. */ + if( dir == 3 ) { + for( i = 0; i < 3; i++ ) { + neweye[ i ] = e[ i ]*cosa - emod*f[ i ]*sina + cam->target_vector[ i ]; + } + + } else { + for( i = 0; i < 3; i++ ) { + neweye[ i ] = e[ i ]*cosa + emod*f[ i ]*sina + cam->target_vector[ i ]; + } + } + } + +/* Modify the camera eye vector, retaining the other camera settings. */ + result = PG3DSetCamera( neweye, cam->target_vector, cam->up_vector, + cam->screen_distance ); + } + + return result; +} + +int PG3DRotateTarget( int axis, float angle ){ +/* +*+ +* Name: +* PG3DRotateTarget + +* Purpose: +* Move the target by rotating the (u,v,w) coordinate system. + +* Synopsis: +* #include "grf3d.h" +* int PG3DRotateTarget( int dir, float angle ) + +* Description: +* This function modifies the camera target position for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. +* +* The (u,v,w) coordinate system that defines the position of the +* target relative to the eye is rotated, and the target is placed at +* the end of the "w" axis. The eye position is left unchanged. This +* is equivalent to a roll, pitch or yaw of the camera. + +* Parameters: +* axis +* The axis around which to rotate: +* 1 - the U axis (pitch) +* 2 - the V axis (yaw) +* 3 - the W axis (roll) +* angle +* The angle, in degrees, by which to rotate around the specified +* axis. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + float m[ 9 ], newmat[ 9 ]; + Camera *cam; + int result = 0; + int i, j, k; + float sina, cosa, *p, *p1, *p2; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + result = 1; + +/* Get the cos and sine of the supplied angle. */ + cosa = cos( angle*TWOPI/360 ); + sina = sin( angle*TWOPI/360 ); + +/* Get the 3x3 rotation matrix. */ + if( axis == 1 ) { + m[ 0 ] = 1.0; + m[ 1 ] = 0.0; + m[ 2 ] = 0.0; + m[ 3 ] = 0.0; + m[ 4 ] = cosa; + m[ 5 ] = -sina; + m[ 6 ] = 0.0; + m[ 7 ] = sina; + m[ 8 ] = cosa; + + } else if( axis == 2 ) { + m[ 0 ] = cosa; + m[ 1 ] = 0.0; + m[ 2 ] = -sina; + m[ 3 ] = 0.0; + m[ 4 ] = 1.0; + m[ 5 ] = 0.0; + m[ 6 ] = sina; + m[ 7 ] = 0.0; + m[ 8 ] = cosa; + + } else if( axis == 3 ) { + m[ 0 ] = cosa; + m[ 1 ] = -sina; + m[ 2 ] = 0.0; + m[ 3 ] = sina; + m[ 4 ] = cosa; + m[ 5 ] = 0.0; + m[ 6 ] = 0.0; + m[ 7 ] = 0.0; + m[ 8 ] = 1.0; + + } else { + result = 0; + } + +/* If the axis value is OK, multiple the existing w2c_matrix by the + rotation matrix to get the new camera matrix. The w2c_matrix is a + 3x3 matrix that rotates vectors in the (x,y,z) system into vectors + in the (u,v,w) system. Each row in the matrix is a unit vector + along the u, v or w axes. */ + p = newmat; + for( i = 0; i < 3; i++ ) { + for( j = 0; j < 3; j++, p++ ) { + p1 = m + i*3; + p2 = cam->w2c_matrix + j; + *p = 0.0; + for( k = 0; k < 3; k++ ) { + *p += (*p1) * (*p2); + p1++; + p2 += 3; + } + } + } + +/* Store the new camera matrix. */ + memcpy( cam->w2c_matrix, newmat, sizeof(float)*9 ); + +/* Store corresponding new values for the target and up vectors. */ + for( k = 0; k < 3; k++ ) { + cam->target_vector[ k ] = cam->eye_vector[ k ] + + newmat[ 6 + k ]*cam->screen_distance; + } + memcpy( cam->up_vector, newmat + 3, 3*sizeof( float ) ); + + } + + return result; +} + +int PG3DForward( float distance ){ +/* +*+ +* Name: +* PG3DForward + +* Purpose: +* Move the eye forward towards the target. + +* Synopsis: +* #include "grf3d.h" +* int PG3DForward( float distance ) + +* Description: +* This function modifies the camera eye position for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. +* +* The eye is moved forward by a given distance towards the target +* point, and the target point is also moved forward so that the +* distance between eye and target remains unchanged. + +* Parameters: +* distance +* The distance to move the eye and target, given as a fraction of +* the distance between the eye and the target. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + int i; + float e[3], newtarg[3], neweye[3]; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + +/* Get the vector from the eye to the target. */ + vectorSub( cam->target_vector, cam->eye_vector, e ); + +/* Find the new eye and target positions. */ + for( i = 0; i < 3; i++ ){ + neweye[ i ] = cam->eye_vector[ i ] + e[ i ]*distance; + newtarg[ i ] = cam->target_vector[ i ] + e[ i ]*distance; + } + +/* Modify the camera eye and target vectors, retaining the other camera + settings. */ + result = PG3DSetCamera( neweye, newtarg, cam->up_vector, + cam->screen_distance ); + } + + return result; +} + + +int PG3DFindNearest( int n, float *x, float *y, float *z, int *iclose ){ +/* +*+ +* Name: +* PG3DFindNearest + +* Purpose: +* Find the closest point to the eye. + +* Synopsis: +* #include "grf3d.h" +* int PG3DFindNearest( int n, float *x, float *y, float *z, int *iclose ) + +* Description: +* This function checks every supplied point and returns the index of +* the point that is closest to the eye. + +* Parameters: +* n +* The number of points to check. +* x +* Pointer to an array of "n" X values. +* y +* Pointer to an array of "n" Y values. +* z +* Pointer to an array of "n" Z values. +* iclose +* Pointer to an int in which to return the index of hte nearest +* point. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + int i; + float c[3], v[3]; + float d; + float dmin; + + *iclose = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + result = 1; + +/* Loop through all the supplied positions. */ + dmin = FLT_MAX; + for( i = 0; i < n; i++ ) { + +/* Get the required distance. */ + v[ 0 ] = x[ i ]; + v[ 1 ] = y[ i ]; + v[ 2 ] = z[ i ]; + vectorSub( v, cam->eye_vector, c ); + d = vectorModulus( c ); + +/* If this is the smallest distance so far, remember it. */ + if( d < dmin ) { + dmin = d; + *iclose = i; + } + } + } + + return result; +} + + +int PG3DSetTarget( float target[3] ){ +/* +*+ +* Name: +* PG3DSetTarget + +* Purpose: +* Store a new camera target position for the current PGPLOT device. + +* Synopsis: +* #include "grf3d.h" +* int PG3DSetTarget( float target[3] ) + +* Description: +* This function modifies the camera target position for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. + +* Parameters: +* target +* The position vector of the camera's "target", in 3D world coordinates. +* Zero is returned if the new target position is the same as the +* existing camera eye position. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + +/* If so, modify the camera values, using the supplied target position but + retaining the other camera settings. */ + result = PG3DSetCamera( cam->eye_vector, target, cam->up_vector, + cam->screen_distance ); + } + + return result; +} + + +int PG3DSetUp( float up[3] ){ +/* +*+ +* Name: +* PG3DSetUp + +* Purpose: +* Store a new camera up vector for the current PGPLOT device. + +* Synopsis: +* #include "grf3d.h" +* int PG3DSetUp( float up[3] ) + +* Description: +* This function modifies the camera up vector for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. + +* Parameters: +* up +* The new up vector, in 3D world coordinates. Zero is returned if +* the new up vector is parallel to the line joining the eye and +* the target positions. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + +/* If so, modify the camera values, using the supplied up vector but + retaining the other camera settings. */ + result = PG3DSetCamera( cam->eye_vector, cam->target_vector, up, + cam->screen_distance ); + } + + return result; +} + + +int PG3DSetScreen( float screen ){ +/* +*+ +* Name: +* PG3DSetScreen + +* Purpose: +* Store a new camera screen distance for the current PGPLOT device. + +* Synopsis: +* #include "grf3d.h" +* int PG3DSetScreen( float screen ) + +* Description: +* This function modifies the camera screen distance for the current +* PGPLOT device. Other camera settings are left unchanged. See +* PG3DSetCamera for more details. + +* Parameters: +* screen +* The distance from the camera's eye to the projection screen in +* 3D world coordinate units. If this is zero, then an orthographic +* projection is used. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +* - This function can only be called to modify an existing Camera. +* Consequently it returns zero if a camera has not already been set +* for the current PGPLOT device by calling PG3DSetCamera. +*- +*/ + +/* Local Variables: */ + Camera *cam; + int result = 0; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 1 ); + if( cam ) { + +/* If so, modify the camera values, using the supplied screen distance but + retaining the other camera settings. */ + result = PG3DSetCamera( cam->eye_vector, cam->target_vector, + cam->up_vector, screen ); + } + + return result; +} + +int PG3DAutoCamera( float lbnd[3], float ubnd[3] ){ +/* +*+ +* Name: +* PG3DAutoCamera + +* Purpose: +* Set up a default camera to view a given box of 3D world coords. + +* Synopsis: +* #include "grf3d.h" +* int PG3DAutoCamera( float lbnd[3], float ubnd[3] ) + +* Description: +* This function sets up the camera and the 2D PGPLOT window for the +* current device so that it produces a default view of a specified +* volume of 3D world coordinate space. + +* Parameters: +* lbnd +* The lower bounds of the volume of 3D world coordinates that +* is to be visible using the camera and 2D PGPLOT window. +* ubnd +* The upper bounds of the volume of 3D world coordinates that +* is to be visible using the camera and 2D PGPLOT window. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - Zero is returned if no PGPLOT device has been opened prior to +* calling this function. +*- +*/ + +/* Local Variables: */ + float target[3], eye[3], up[3], screen, dx, dy, dz, hlo, hhi, rlo, rhi; + float x[8], y[8], z[8], h[8], r[8]; + Camera *cam; + int result = 0; + int i; + +/* Get a pointer to the Camera structure for the current PGPLOT device. + Return without action if no PGPLOT device is open. */ + cam = getCamera( 0 ); + if( cam ) { + +/* The target position (i.e. the position towards which the camera is + looking) is the middle of the volume. */ + target[ 0 ] = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); + target[ 1 ] = 0.5*( lbnd[ 1 ] + ubnd[ 1 ] ); + target[ 2 ] = 0.5*( lbnd[ 2 ] + ubnd[ 2 ] ); + +/* The eye is slightly offset from a corner view. */ + eye[ 0 ] = 0.85*ubnd[ 0 ] + 0.15*lbnd[ 0 ]; + eye[ 1 ] = 0.75*ubnd[ 1 ] + 0.25*lbnd[ 1 ]; + eye[ 2 ] = 0.75*ubnd[ 2 ] + 0.25*lbnd[ 2 ]; + +/* The eye is seven times the size of the box away from the box centre. */ + eye[ 0 ] = 7*(eye[ 0 ] - target[ 0 ] ) + target[ 0 ]; + eye[ 1 ] = 7*(eye[ 1 ] - target[ 1 ] ) + target[ 1 ]; + eye[ 2 ] = 7*(eye[ 2 ] - target[ 2 ] ) + target[ 2 ]; + +/* The up vector is paralle to the Z axis. */ + up[ 0 ] = 0.0; + up[ 1 ] = 0.0; + up[ 2 ] = 1.0; + +/* The screen is at the centre of the box. */ + dx = eye[ 0 ] - target[ 0 ]; + dy = eye[ 1 ] - target[ 1 ]; + dz = eye[ 2 ] - target[ 2 ]; + screen = sqrtf( dx*dx + dy*dy + dz*dz ); + +/* Set the camera. */ + if( PG3DSetCamera( eye, target, up, screen ) ) { + +/* Get the 3D World coords at the corners of the volume. */ + x[ 0 ] = ubnd[ 0 ]; + x[ 1 ] = ubnd[ 0 ]; + x[ 2 ] = lbnd[ 0 ]; + x[ 3 ] = lbnd[ 0 ]; + x[ 4 ] = ubnd[ 0 ]; + x[ 5 ] = ubnd[ 0 ]; + x[ 6 ] = lbnd[ 0 ]; + x[ 7 ] = lbnd[ 0 ]; + + y[ 0 ] = lbnd[ 1 ]; + y[ 1 ] = ubnd[ 1 ]; + y[ 2 ] = ubnd[ 1 ]; + y[ 3 ] = lbnd[ 1 ]; + y[ 4 ] = lbnd[ 1 ]; + y[ 5 ] = ubnd[ 1 ]; + y[ 6 ] = ubnd[ 1 ]; + y[ 7 ] = lbnd[ 1 ]; + + z[ 0 ] = lbnd[ 2 ]; + z[ 1 ] = lbnd[ 2 ]; + z[ 2 ] = lbnd[ 2 ]; + z[ 3 ] = lbnd[ 2 ]; + z[ 4 ] = ubnd[ 2 ]; + z[ 5 ] = ubnd[ 2 ]; + z[ 6 ] = ubnd[ 2 ]; + z[ 7 ] = ubnd[ 2 ]; + +/* Transform these into screen coordinates. */ + if( transform( cam, 8, x, y, z, h, r ) ) { + +/* Find the bounds in h and r of the projection of the volume. */ + hlo = FLT_MAX; + hhi = -FLT_MAX; + rlo = FLT_MAX; + rhi = -FLT_MAX; + + for( i = 0; i < 8; i++ ) { + if( h[ i ] < hlo ) hlo = h[ i ]; + if( h[ i ] > hhi ) hhi = h[ i ]; + if( r[ i ] < rlo ) rlo = r[ i ]; + if( r[ i ] > rhi ) rhi = r[ i ]; + } + +/* Extend these bounds by 5% at each end */ + dx = 0.05*( hhi - hlo ); + hhi += dx; + hlo -= dx; + + dy = 0.05*( rhi - rlo ); + rhi += dy; + rlo -= dy; + +/* If the box has non-zero area, set it as the 2D PGPLOT window, and + indicate success. */ + if( rlo < rhi && hlo < hhi ) { + ccpgswin( hlo, hhi, rlo, rhi ); + result = 1; + } + } + } + } + return result; +} + + + + + +/* Private functions for this module */ +/* ================================= */ + +static int TextCam( Camera *textcam, float ref[3], float tx[3], float ty[3], + float tz[3] ){ +/* +* Name: +* TextCam + +* Purpose: +* Create a Camera that converts 3D text plane coordinates into 2D world +* coordinates. + +* Synopsis: +* #include "grf3d.h" +* int TextCam( Camera *textcam, float ref[3], float tx[3], float ty[3], +* float tz[3] ) + +* Description: +* This function initialises the contents of a supplied Camera +* structure so that the Camera describes the transformation from 3D +* "text plane" coordinates to 2D PGPLOT world coordinates. The text +* plane coordinate system is defined by three vectors along its x, y +* and z axes, and an origin position. +* +* Text plane coordinates describe a plane upon which 2D graphics such +* as text is drawn. The X axis is parallel to the text base line, the +* Y axis is the text up vector, and the Z axis is perpendicular to +* the text, passing from the back of the text to the front of the text. + +* Parameters: +* textcam +* The Camera structure which is to be modified. +* ref +* The (x,y,z) coordinates at the text plane origin. +* tx +* A unit vector (expressed in 3D world coords) along the text plane +* X axis. This is parallel to the text base line. +* ty +* A unit vector (expressed in 3D world coords) along the text plane +* Y axis. This is parallel to the projectionof ht eup vector on to +* the text plane. +* tz +* A unit vector (expressed in 3D world coords) along the text plane +* Z axis. This is perpendicular to the text plane, passing from +* the back of the text to the front of the text. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +*/ + + +/* Local Variables: */ + Camera *cam; + float dx, dy, dz; + int i; + float a, b, c; + +/* Get the Camera for the current device identifier. Abort if no camera + is available. This camera describes the transformation from 3D world + coordinates (x,y,z) to 2D world coordinates (screen coordinates) (h,r). */ + cam = getCamera( 1 ); + if( !cam ) return 0; + +/* Create a Camera structure that describes the transformation from + text plane coordinates to 2D world coords, putting the origin of text + plane coordinates at the given reference position. */ + dx = cam->eye_vector[ 0 ] - ref[ 0 ]; + dy = cam->eye_vector[ 1 ] - ref[ 1 ]; + dz = cam->eye_vector[ 2 ] - ref[ 2 ]; + + textcam->eye_vector[ 0 ] = tx[ 0 ]*dx + tx[ 1 ]*dy + tx[ 2 ]*dz; + textcam->eye_vector[ 1 ] = ty[ 0 ]*dx + ty[ 1 ]*dy + ty[ 2 ]*dz; + textcam->eye_vector[ 2 ] = tz[ 0 ]*dx + tz[ 1 ]*dy + tz[ 2 ]*dz; + + for( i = 0; i < 8; i += 3 ) { + a = cam->w2c_matrix[ i ]; + b = cam->w2c_matrix[ i + 1 ]; + c = cam->w2c_matrix[ i + 2 ]; + textcam->w2c_matrix[ i ] = a*tx[ 0 ] + b*tx[ 1 ] + c*tx[ 2 ]; + textcam->w2c_matrix[ i + 1 ] = a*ty[ 0 ] + b*ty[ 1 ] + c*ty[ 2 ]; + textcam->w2c_matrix[ i + 2 ] = a*tz[ 0 ] + b*tz[ 1 ] + c*tz[ 2 ]; + } + + textcam->screen_distance = cam->screen_distance; + textcam->ok_flag = CAMERA_OK; + + return 1; +} + +static int Polygon( int nside, float *vx, float *vy, float *vz, float ref[3], + float tx[3], float ty[3], float tz[3] ){ +/* +* Name: +* Polygon + +* Purpose: +* Draw a regular polygon. + +* Synopsis: +* #include "grf3d.h" +* int Polygon( int nside, float *vx, float *vy, float *vz, float ref[3], +* float tx[3], float ty[3], float tz[3] ) + +* Description: +* This function draws a polygon centred at a given position on a +* given plane in 3D world coords, using a specified up-vector. The +* polygon vertices are specified in text plane coordinates via vx, +* vy and vz. + +* Parameters: +* nside +* Number of sides for the polygon. Numbers higher than 32 are +* treated as 32. +* vx +* Pointer to an array of "nside" text plane X axis values. +* vy +* Pointer to an array of "nside" text plane Y axis values. +* vz +* Pointer to an array of "nside" text plane Z axis values. +* ref +* The (x,y,z) coordinates at the polygon centre. +* tx +* A unit vector (expressed in 3D world coords) along the text plane +* X axis. This is parallel to the text base line. +* ty +* A unit vector (expressed in 3D world coords) along the text plane +* Y axis. This is parallel to the projectionof ht eup vector on to +* the text plane. +* tz +* A unit vector (expressed in 3D world coords) along the text plane +* Z axis. This is perpendicular to the text plane, passing from +* the back of the text to the front of the text. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +*/ + + +/* Local Variables: */ + Camera *cam; + Camera newcam; + float h[ MXSIDE ], r[ MXSIDE ]; + +/* Get the Camera for the current device identifier. Abort if no camera + is available. */ + cam = getCamera( 1 ); + if( !cam ) return 0; + +/* Check the number of points. */ + if( nside > MXSIDE) return 0; + +/* Create a Camera structure that describes the transformation from + text plane coordinates to 2D world coords, putting the origin of text + plane coordinates at the given reference position. */ + if( !TextCam( &newcam, ref, tx, ty, tz ) ) return 0; + +/* Transform the given text plane coordinates into 2D world coordinates. */ + if( !transform( &newcam, nside, vx, vy, vz, h, r ) ) return 0; + +/* Draw the polygon. */ + ccpgpoly( nside, h, r ); + +/* If we get here we have succeeded so return a non-zero value. */ + return 1; +} + +static int Text( int *list, int nlist, float ref[3], const char *just, + float tx[3], float ty[3], float tz[3] ){ +/* +* Name: +* Text + +* Purpose: +* Draw a character string. + +* Synopsis: +* #include "grf3d.h" +* int Text( int *list, int nlist, float ref[3], const char *just, +* float tx[3], float ty[3], float tz[3] ) + +* Description: +* This function displays a symbol list at a given position on a given +* plane in 3D world coords, using a specified justification and up-vector. + +* Parameters: +* list +* Pointer to an array of pgplot symbol values. +* nlist +* Length of the "list" array. +* ref +* The reference (x,y,z) coordinates. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", or 'B' for "bottom", and specifies the +* vertical location of the reference position. Note, "bottom" +* corresponds to the base-line of normal text. Some characters +* (eg "y", "g", "p", etc) descend below the base-line. The second +* character may be 'L' for "left", 'C' for "centre", or 'R' +* for "right", and specifies the horizontal location of the +* reference position. If the string has less than 2 characters +* then 'C' is used for the missing characters. +* tx +* A unit vector (expressed in 3D world coords) along the text plane +* X axis. This is parallel to the text base line. +* ty +* A unit vector (expressed in 3D world coords) along the text plane +* Y axis. This is parallel to the projection of the up vector on to +* the text plane. +* tz +* A unit vector (expressed in 3D world coords) along the text plane +* Z axis. This is perpendicular to the text plane, passing from +* the back of the text to the front of the text. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - This routine does not recognise PGPLOT escape sequences. +* - A NULL value for "just" causes a value of "CC" to be used. +*/ + +/* Local Constants: */ +#define MXLEN 256 + +/* Local Variables: */ + Camera *cam; + Camera newcam; + float ch; + float tm, txc, tyc; + float txleft, tybase; + float xt[ 150 ], yt[ 150 ], zt[ 150 ], h[ 150 ], r[ 150 ]; + float xb[3], yb[3], zb[3], bl[3]; + int clip; + int i; + int j; + int k; + int unused; + int xygrid[ 300 ]; + +/* If there is nothing to plot return without error. */ + if( nlist == 0 ) return 1; + +/* Find the 3D world coordinates at the left hand end of the text + baseline. */ + if( !TxExt( list, nlist, ref, just, tx, ty, tz, xb, yb, zb, bl ) ) return 0; + +/* Get the Camera for the current device identifier. Abort if no camera + is available. */ + if( ! (cam = getCamera( 1 ) ) ) return 0; + +/* Create a Camera structure that describes the transformation from + text plane coordinates to 2D world coords. */ + if( !TextCam( &newcam, ref, tx, ty, tz ) ) return 0; + +/* Save the current clipping flag, and ensure clipping is off. */ + ccpgqclp( &clip ); + ccpgsclp( 0 ); + +/* Calculate the text plane X coord of the left hand edge of the first + character. */ + txleft = tx[ 0 ]*( bl[ 0 ] - ref[ 0 ] ) + + tx[ 1 ]*( bl[ 1 ] - ref[ 1 ] ) + + tx[ 2 ]*( bl[ 2 ] - ref[ 2 ] ); + +/* Calculate the text plane Y coord at the text baseline. */ + tybase = ty[ 0 ]*( bl[ 0 ] - ref[ 0 ] ) + + ty[ 1 ]*( bl[ 1 ] - ref[ 1 ] ) + + ty[ 2 ]*( bl[ 2 ] - ref[ 2 ] ); + +/* Get the character height in world coordinate units. A PGPLOT + character height of 1.0 corresponds to 1/40 of the 2D window height. */ + ch = getCharHeight(); + +/* Get the polylines that correspond to the first symbol. */ + ccgrsyxd( list[ 0 ], xygrid, &unused ); + +/* Create a linear transformation that maps the font grid coordinate + system used by grsyxd onto text plane coordinates. This transformation + will be different for each character in the string. The initial + transformation set up now is appropriate for the first character. The + mapping is: + + Text_x = txc + tm*Font_x + Text_y = tyc + tm*Font_y + +*/ + tm = ch/( xygrid[ 2 ] - xygrid[ 1 ] ); + tyc = tybase - tm*xygrid[ 1 ]; + txc = txleft - tm*xygrid[ 3 ]; + +/* Loop round each symbol. */ + for( i = 0; i < nlist; i++ ) { + +/* Loop round each polyline that forms a segment of the character */ + k = 5; + while( 1 ) { + +/* Map the polyline vertices into text plane coordinates. */ + j = 0; + while( j < 150 ){ + if( xygrid[ k ] != -64 ) { + xt[ j ] = txc + tm*xygrid[ k++ ]; + yt[ j ] = tyc + tm*xygrid[ k++ ]; + zt[ j++ ] = 0.0; + } else { + break; + } + } + +/* Map the text plane coordinates into 2D world coordinates. */ + if( j > 0 ) { + (void) transform( &newcam, j, xt, yt, zt, h, r ); + +/* Draw the polyline. */ + ccpgline( j, h, r ); + } + +/* If this is the last segment in the character, pass on to the next + character. */ + if( xygrid[ k + 1 ] == -64 ) break; + +/* Otherwise, skip over the end markers in the xygrid array, and go on to + plot the next polyline segment. */ + k += 2; + } + +/* If this is not the last symbol... */ + if( i != nlist - 1 ) { + +/* Set the text x value at which to place the left edge of the next + character. This is the right hand edge of the character just drawn. */ + txleft += tm*( xygrid[ 4 ] - xygrid[ 3 ] ); + +/* Get the polylines that correspond to the next symbol. */ + ccgrsyxd( list[ i + 1 ], xygrid, &unused ); + +/* Modify the transformation from font grid coords to text plane coords + so that it is appropriate for the next character in the string. */ + txc = txleft - tm*xygrid[ 3 ]; + } + +/* Next symbol. */ + } + +/* Re-instate original clipping flag. */ + ccpgsclp( clip ); + +/* If we arrive here, we have been successful, so return a non-zero + value. */ + return 1; + +/* Clear local constants. */ +#undef MXLEN +} + +static int TxExt( int *list, int nlist, float ref[3], const char *just, + float tx[3], float ty[3], float tz[3], float *xb, float *yb, + float *zb, float bl[3] ){ +/* +* Name: +* TxExt + +* Purpose: +* Get the extent of a character string. + +* Synopsis: +* #include "grf3d.h" +* int TxExt( int *list, int nlist, float ref[3], const char *just, +* float tx[3], float ty[3], float tz[3], float *xb, float *yb, +* float *zb, float bl[3] ) + +* Description: +* This function returns the corners of a box which would enclose the +* supplied symbol list if it were displayed using Text. +* +* The returned box includes any leading or trailing spaces. + +* Parameters: +* list +* Pointer to an array of pgplot symbol numbers. +* nlist +* The length of the "list" array. +* ref +* The reference (x,y,z) coordinates. +* just +* A character string which specifies the location within the +* text string which is to be placed at the reference position +* given by x and y. The first character may be 'T' for "top", +* 'C' for "centre", 'B' for "baseline", or "M" for "bottom", and +* specifies the vertical location of the reference position. Note, +* "baseline" corresponds to the base-line of normal text. Some +* characters (eg "y", "g", "p", etc) descend below the base-line, +* and so "M" and "B" will produce different effects for such +* characters. The second character may be 'L' for "left", 'C' for +* "centre", or 'R' for "right", and specifies the horizontal +* location of the reference position. If the string has less than +* 2 characters then 'C' is used for the missing characters. +* tx +* A unit vector (expressed in 3D world coords) along the text plane +* X axis. This is parallel to the text base line. +* ty +* A unit vector (expressed in 3D world coords) along the text plane +* Y axis. This is parallel to the projectionof ht eup vector on to +* the text plane. +* tz +* A unit vector (expressed in 3D world coords) along the text plane +* Z axis. This is perpendicular to the text plane, passing from +* the back of the text to the front of the text. +* xb +* An array of 4 elements in which to return the x coordinate of +* each corner of the bounding box. +* yb +* An array of 4 elements in which to return the y coordinate of +* each corner of the bounding box. +* zb +* An array of 4 elements in which to return the z coordinate of +* each corner of the bounding box. +* bl +* The 3D world coordinates at the left hand end of the text +* baseline. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. + +* Notes: +* - The order of the corners is anti-clockwise starting at the +* bottom left when viewing the text normally (i.e. face on). +* - This routine does not recognise PGPLOT escape sequences. +* - A NULL value for "just" causes a value of "CC" to be used. +*/ + +/* Local Constants: */ +#define MXLEN 256 + +/* Local Variables: */ + float ch; + float txlo, txhi, tylo, tyhi, tyzero; + float tm; + float w; + int i; + int unused; + int xygrid[ 300 ]; + int gylo, gyhi, width; + +/* Initialise the returned values to indicate no box available. */ + for( i = 0; i < 4; i++ ){ + xb[ i ] = 0.0; + yb[ i ] = 0.0; + zb[ i ] = 0.0; + } + +/* If there is nothing to plot return without error. */ + if( nlist == 0 ) return 1; + +/* We now find the bounding box of the text in "text plane coordinates". + These are (tx,ty,tz) axes that span the plane upon which the text is + writtens. The origin of (tx,ty,tz) is at the supplied 3D reference + position, the X axis increases along the text baseline, and Y axis + increases along the text up vector, and Z increases from the back + of the text to the front of the text (all are measured in 3D world + coord units). We first find the bounds of the text in these text plane + coordinates, assuming that the bottom left of the text baseline is + placed at the given reference position (i.e. at the origiin of text + plane coordinates). */ + +/* Get the character height in world coordinate units. A PGPLOT + character height of 1.0 corresponds to 1/40 of the 2D window height. */ + ch = getCharHeight(); + +/* Initialise the Y bounds of the text bounding box in grid coords. */ + gylo = INT_MAX; + gyhi = -INT_MAX; + +/* Initialise things. */ + width = 0; + tm = 1.0; + +/* Loop round each symbol. */ + for( i = 0; i < nlist; i++ ) { + +/* Get the polylines that correspond to this symbol. */ + ccgrsyxd( list[ i ], xygrid, &unused ); + +/* If this is the first symbol, set the scaling factor that converts + grid units to text plane units. */ + if( i == 0 ) tm = ch/( xygrid[ 2 ] - xygrid[ 1 ] ); + +/* Note the highest and lowest y grid value. */ + w = xygrid[ 2 ] - xygrid[ 1 ]; + if( w > gyhi ) gyhi = w; + + w = xygrid[ 0 ] - xygrid[ 1 ]; + if( w < gylo ) gylo = w; + +/* Increment the total width of the string in grid units. */ + width += xygrid[ 4 ] - xygrid[ 3 ]; + } + +/* Set up the bounding box in text plane coordinates. */ + txlo = 0.0; + txhi = width*tm; + tylo = gylo*tm; + tyhi = gyhi*tm; + tyzero = 0.0; + +/* Adjust the text plane bounding box to take account of the specified + text justification. The above process implicitly assumed a + justifiation of "BL". */ + if( !just || just[ 0 ] == 'C' || just[ 0 ] == 0 ){ + w = 0.5*( tyhi + tylo ); + tylo -= w; + tyhi -= w; + tyzero -= w; + + } else if( just[ 0 ] == 'T' ){ + w = tyhi; + tylo -= w; + tyhi -= w; + tyzero -= w; + + } else if( just[ 0 ] == 'M' ){ + w = -tylo; + tylo += w; + tyhi += w; + tyzero += w; + + } else if( just[ 0 ] != 'B' ) { + astError( AST__GRFER, "astG3DTxExt: Justification string '%s' " + "is invalid.", just ); + return 0; + } + + if( !just || just[ 1 ] == 'C' || just[ 1 ] == 0 ){ + w = 0.5*( txhi + txlo ); + txlo -= w; + txhi -= w; + + } else if( just[ 1 ] == 'R' ){ + w = txhi; + txlo -= w; + txhi -= w; + + } else if( just[ 1 ] == 'L' ){ + w = txlo; + txlo -= w; + txhi -= w; + + } else { + astError( AST__GRFER, "astG3DTxExt: Justification string '%s' " + "is invalid.", just ); + return 0; + } + +/* Use the supplied text plane axis vectors to transform the corners of + the text plane bounding box into 3D world coordinates. */ + xb[ 0 ] = tx[ 0 ]*txlo + ty[ 0 ]*tylo + ref[ 0 ]; + yb[ 0 ] = tx[ 1 ]*txlo + ty[ 1 ]*tylo + ref[ 1 ]; + zb[ 0 ] = tx[ 2 ]*txlo + ty[ 2 ]*tylo + ref[ 2 ]; + + xb[ 1 ] = tx[ 0 ]*txhi + ty[ 0 ]*tylo + ref[ 0 ]; + yb[ 1 ] = tx[ 1 ]*txhi + ty[ 1 ]*tylo + ref[ 1 ]; + zb[ 1 ] = tx[ 2 ]*txhi + ty[ 2 ]*tylo + ref[ 2 ]; + + xb[ 2 ] = tx[ 0 ]*txhi + ty[ 0 ]*tyhi + ref[ 0 ]; + yb[ 2 ] = tx[ 1 ]*txhi + ty[ 1 ]*tyhi + ref[ 1 ]; + zb[ 2 ] = tx[ 2 ]*txhi + ty[ 2 ]*tyhi + ref[ 2 ]; + + xb[ 3 ] = tx[ 0 ]*txlo + ty[ 0 ]*tyhi + ref[ 0 ]; + yb[ 3 ] = tx[ 1 ]*txlo + ty[ 1 ]*tyhi + ref[ 1 ]; + zb[ 3 ] = tx[ 2 ]*txlo + ty[ 2 ]*tyhi + ref[ 2 ]; + +/* Also transform the text plane coordinates at the bottom left of the + text baseline into 3D world coordinates. */ + bl[ 0 ] = tx[ 0 ]*txlo + ty[ 0 ]*tyzero + ref[ 0 ]; + bl[ 1 ] = tx[ 1 ]*txlo + ty[ 1 ]*tyzero + ref[ 1 ]; + bl[ 2 ] = tx[ 2 ]*txlo + ty[ 2 ]*tyzero + ref[ 2 ]; + +/* If we get here, we have been succesful, so return a non-zero value. */ + return 1; + +/* Clear local constants. */ +#undef MXLEN +} + +static float getCharHeight( void ){ +/* +* Name: +* getCharHeight + +* Purpose: +* Get the current text height setting. + +* Synopsis: +* #include "grf3d.h" +* float getCharHeight( void ) + +* Description: +* This function returns the PGPLOT character height, scaled into +* world coordinate units. + +* Returned Value: +* The character height, in world coordinate units. + +*/ + +/* Local Variables: */ + float wx1, wx2, wy1, wy2; + float ch; + +/* Get the bounds of the PGPLTO 2D window. */ + ccpgqwin( &wx1, &wx2, &wy1, &wy2 ); + +/* Get the normalised PGPLOT character height. */ + ccpgqch( &ch ); + +/* A PGPLOT character height of 1.0 corresponds to 1/40 of the 2D window + height. Scale the normalised character height into world coordinate + units, and return it. */ + return ch*fabs( wy1 - wy2 )/40.0; + +} + +static int getTextAxes( float ref[3], float up[3], float norm[3], + const char *just, float tx[3], float ty[3], + float tz[3], char newjust[3] ){ +/* +* Name: +* getTextAxes + +* Purpose: +* Get unit vectors along the text plane coordinate axes. + +* Synopsis: +* #include "grf3d.h" +* int getTextAxes( float ref[3], float up[3], float norm[3], +* const char *just, float tx[3], float ty[3], +* float tz[3], char newjust[3] ) + +* Description: +* This function returns three unit vectors that define the axes of a +* 3D Cartesian coordinate system known as "text plane coordinates". +* These axes span the plane upon which text (or other graphics) is to +* be written. The origin is at the supplied 3D reference position, the +* X axis increases along the text baseline, and Y axis increases along +* the text up vector, and Z increases from the back of the text to the +* front of the text (all are measured in 3D world coord units). +* +* The returned vectors are reversed if this will result in text +* appearing more "normal" (i.e. viewed from the front rather than +* the back, and viewed upright rather thna upside down). If the +* vectors are reversed, the justification string is also changed so +* that the text occupies the requested area on the screen. + +* Parameters: +* ref +* The reference (x,y,z) coordinates. +* up +* The (x,y,z) up-vector for the text. The actual up vector used is +* the projection of the supplied vector onto the plane specified by +* "norm". +* norm +* The (x,y,z) components of a vector that is normal to the plane +* containing the text. The given vector passes through the text +* from the back to the front. If all components of this vector are +* zero, then a normal vector pointing towards the camera eye is used. +* just +* The requested text justification, as supplied to astG3DText. +* tx +* A unit vector along the text plane X axis. +* ty +* A unit vector along the text plane X axis. +* tz +* A unit vector along the text plane X axis. +* newjust +* The text justification to use. + +* Returned Value: +* A value of 0 is returned if an error occurs, and 1 is returned +* otherwise. +*/ + +/* Local Variables: */ + Camera *cam; + float eye[3]; + +/* Initialise the returned justification to equal the supplied + justification, supplying defaults if required. . */ + if( just ) { + strncpy( newjust, just, 2 ); + if( !newjust[ 0 ] ) newjust[ 0 ] = 'C'; + if( !newjust[ 1 ] ) newjust[ 1 ] = 'C'; + newjust[ 2 ] = 0; + } else { + strcpy( newjust, "CC" ); + } + +/* Get the Camera for the current device identifier. Abort if no camera + is available. */ + if( !( cam = getCamera( 1 ) ) ) return 0; + +/* Calculate the vector from the reference position to the eye, and store + it in "eye". */ + vectorSub( cam->eye_vector, ref, eye ); + +/* Create unit vectors along the three axes of the text plane coordinate + system. These unit vectors are represented in terms of the 3D world + coordinate axes. The text Z axis is parallel to the supplied "norm" + vector. */ + tz[ 0 ] = norm[ 0 ]; + tz[ 1 ] = norm[ 1 ]; + tz[ 2 ] = norm[ 2 ]; + +/* Attempt to normalise the "tz" vector. If it has zero length, use the + offset from the reference point to the eye. */ + if( ! vectorNorm( tz ) ){ + +/* Use the "eye" vector calculated above as the text plane Z axis. */ + tz[ 0 ] = eye[ 0 ]; + tz[ 1 ] = eye[ 1 ]; + tz[ 2 ] = eye[ 2 ]; + } + +/* Find vectors along the text plane x and y axes. */ + vectorProduct( up, tz, tx ); + vectorProduct( tz, tx, ty ); + +/* Normalise the three text plane axis vectors. If any vector has zero + length, abort. */ + if( !vectorNorm( tx ) || !vectorNorm( ty ) || !vectorNorm( tz ) ) return 0; + +/* We now reverse text plane vectors if this will help ther text to be + viewed "normally" on the screen. If the existing vectors cause the + text to be viewed from the back rather than the front, reverse the tx + and tz vectors so that he text is viewed from the front. */ + if( dotProduct( tz, eye ) < 0.0 ) { + tz[ 0 ] = -tz[ 0 ]; + tz[ 1 ] = -tz[ 1 ]; + tz[ 2 ] = -tz[ 2 ]; + tx[ 0 ] = -tx[ 0 ]; + tx[ 1 ] = -tx[ 1 ]; + tx[ 2 ] = -tx[ 2 ]; + +/* The text will have spun around the up vector (i.e. the ty axis), so + modify the horizontal justification so that thex text occupies the same + area on the screen. */ + if( newjust[ 1 ] == 'L' ) { + newjust[ 1 ] = 'R'; + } else if( newjust[ 1 ] == 'R' ) { + newjust[ 1 ] = 'L'; + } + } + +/* If the existing vectors cause the text to be viewed upside down, reverse + the tx and ty vectors so that he text is viewed right way up. */ + if( dotProduct( ty, cam->up_vector ) < 0.0 ) { + ty[ 0 ] = -ty[ 0 ]; + ty[ 1 ] = -ty[ 1 ]; + ty[ 2 ] = -ty[ 2 ]; + tx[ 0 ] = -tx[ 0 ]; + tx[ 1 ] = -tx[ 1 ]; + tx[ 2 ] = -tx[ 2 ]; + +/* The text will have spun around the tz vector (i.e. the viewing vector), + so modify both vertical and horizontal justification so that the text + occupies the same area on the screen. */ + if( newjust[ 0 ] == 'B' || newjust[ 0 ] == 'M' ) { + newjust[ 0 ] = 'T'; + } else if( newjust[ 0 ] == 'T' ) { + newjust[ 0 ] = 'M'; + } + + if( newjust[ 1 ] == 'L' ) { + newjust[ 1 ] = 'R'; + } else if( newjust[ 1 ] == 'R' ) { + newjust[ 1 ] = 'L'; + } + } + +/* If we arraive here we have been succesful, so return a non-zero value. */ + return 1; +} + +static void getSymbolList( const char *text, int mxlen, int *nlist, int *list ){ +/* +* Name: +* getSymbolList + +* Purpose: +* Get the extent of a character string. + +* Synopsis: +* #include "grf3d.h" +* void getSymbolList( const char *text, int mxlen, int *nlist, int *list ) + +* Description: +* This function converts a supplied text string into a list of PGPLOT +* symbol numbers for the current PGPLOT font. + +* Parameters: +* text +* Pointer to a null-terminated character string. +* mxlen +* The length of the "list" array. +* nlist +* Pointer to an integer in which to place the number of symbol +* values stored in the "list" array. This will be returned equal +* to zero if there are no non-blank characters in the supplied +* string. If there is one or more non-blank characters in "text", +* then the returned list will include any trailing spaces. +* list +* Pointer to an array in which to return the symbol numbers. The +* array should be at least "mxlen" elements long. +*/ + + +/* Local Variables: */ + int font; + int tlen; + +/* Assume we have no symbols. */ + *nlist = 0; + +/* Check there is something to plot. */ + if( astChrLen( text ) > 0 ) { + +/* Find the length of text that can be displayed. */ + tlen = strlen( text ); + if( tlen > mxlen ) tlen = mxlen; + +/* Get the current PGPLOT font. */ + ccpgqcf( &font ); + +/* Convert the supplied string into a list of symbol numbers */ + ccgrsyds( list, nlist, text, tlen, font ); + } +} + +static Camera *getCamera( int check ){ +/* +*+ +* Name: +* getCamera + +* Purpose: +* Return a pointer to the Camera structure for the current PGPLOT +* device. + +* Synopsis: +* #include "grf3d.h" +* Camera getCamera( int check ) + +* Description: +* This function returns a pointer to a static structure that defines the +* position and orientation of the camera in 3D world coords. It can +* be used to transform positions from 3D world coordinates (x,y,z) to +* 2D screen coordinates (h,r). + +* Parameters: +* check +* If non-zero, a check will be made that the Camera has been +* initialised, and NULL will be returned if the Camera has not +* been initialsied. If "check" is zero, a pointer to the Camera +* is returned even if it has not been initialised. + +* Returned Value: +* Pointer to the Camera, or NULL if an error occurs. +*- +*/ + +/* Local Variables: */ + int id; + Camera *cam = NULL; + +/* Get the pgplot current device identifier. Return NULL if no device is + currently open. */ + ccpgqid( &id ); + if( id > 0 && id <= MXDEV ) { + +/* Get a pointer to the required Camera structure. */ + cam = cameras + id - 1; + +/* If required, check that the structure has been initialised. */ + if( check && cam->ok_flag != CAMERA_OK ) cam = NULL; + } + + return cam; +} + +static int transform( Camera *cam, int n, float *x, float *y, float *z, + float *h, float *r ){ +/* +*+ +* Name: +* transform + +* Purpose: +* Transform positions from 3D world coords to 2D screen cooords. + +* Synopsis: +* #include "grf3d.h" +* int transform( Camera *cam, int n, float *x, float *y, float *z, +* float *h, float *r ) + +* Description: +* This function transforms a set of positions from 3D world +* coordinates (x,y,z) to 2D screen coordinates (h,r), using the +* supplied camera. + +* Parameters: +* cam +* Pointer to a structure descibing the projection from 3D world +* coords to 2D screen coords. If NULL, the camera for the current +* PGPLOT device is used. +* n +* The number of positions to transform. +* x +* An array of "n" values for the "x" axis of the 3D world +* coordinate system. +* y +* An array of "n" values for the "y" axis of the 3D world +* coordinate system. +* z +* An array of "n" values for the "z" axis of the 3D world +* coordinate system. +* h +* An array to receive the "n" values for the "h" axis of the 2D +* screen coordinate system. +* r +* An array to receive the "n" values for the "r" axis of the 2D +* screen coordinate system. + +* Returned Value: +* Zero if an error occurs. One otherwise. + +*- +*/ + +/* Local Variables: */ + float dx, dy, dz, u, v, w, f; + int i; + int result = 0; + +/* If no camera was supplied use the camera for the current PGPLOT + device. */ + if( ! cam ) cam = getCamera( 0 ); + +/* Check we now have a usable camera */ + if( cam && cam->ok_flag == CAMERA_OK ) { + result = 1; + +/* Loop round each position. */ + for( i = 0; i < n; i++ ) { + +/* Offset from supplied position to the camera eye. */ + dx = x[ i ] - (cam->eye_vector)[ 0 ]; + dy = y[ i ] - (cam->eye_vector)[ 1 ]; + dz = z[ i ] - (cam->eye_vector)[ 2 ]; + +/* Get the representation of this vector in the (u,v,w) system. */ + u = (cam->w2c_matrix)[ 0 ]*dx + + (cam->w2c_matrix)[ 1 ]*dy + + (cam->w2c_matrix)[ 2 ]*dz; + + v = (cam->w2c_matrix)[ 3 ]*dx + + (cam->w2c_matrix)[ 4 ]*dy + + (cam->w2c_matrix)[ 5 ]*dz; + + w = (cam->w2c_matrix)[ 6 ]*dx + + (cam->w2c_matrix)[ 7 ]*dy + + (cam->w2c_matrix)[ 8 ]*dz; + +/* Find the screen coords, using either a tangent plane or an + orothograhic projection. */ + if( cam->screen_distance != 0.0 ) { + if( w != 0.0 ) { + f = cam->screen_distance/w; + h[ i ] = -f*u; + r[ i ] = f*v; + } else { + h[ i ] = FLT_MAX; + r[ i ] = FLT_MAX; + } + } else { + h[ i ] = -u; + r[ i ] = v; + } + + } + } + return result; +} + + +/* Dot product of a pair of 3-vectors "a" and "b". */ +static float dotProduct( float *a, float *b ){ + return a[ 0 ]*b[ 0 ] + a[ 1 ]*b[ 1 ] + a[ 2 ]*b[ 2 ]; +} + +/* Vector product of a pair of 3-vectors "a" and "b". */ +static void vectorProduct( float *a, float *b, float *c ){ + c[ 0 ] = a[ 1 ]*b[ 2 ] - a[ 2 ]*b[ 1 ]; + c[ 1 ] = a[ 2 ]*b[ 0 ] - a[ 0 ]*b[ 2 ]; + c[ 2 ] = a[ 0 ]*b[ 1 ] - a[ 1 ]*b[ 0 ]; +} + +/* Vector from "b" to "a" (i.e. a minus b) . */ +static void vectorSub( float *a, float *b, float *c ){ + c[ 0 ] = a[ 0 ] - b[ 0 ]; + c[ 1 ] = a[ 1 ] - b[ 1 ]; + c[ 2 ] = a[ 2 ] - b[ 2 ]; +} + +/* Normalises a vector to a unit length. Returns zero if the vector has + zero length, and 1 otherwise. */ +static int vectorNorm( float *a ){ + float d; + d = vectorModulus( a ); + if( d > 0.0 ) { + a[ 0 ] /= d; + a[ 1 ] /= d; + a[ 2 ] /= d; + return 1; + } else { + return 0; + } +} + +/* Return the length of a vector. */ +static float vectorModulus( float *a ){ + return sqrtf( a[ 0 ]*a[ 0 ] + a[ 1 ]*a[ 1 ] + a[ 2 ]*a[ 2 ] ); +} + + + + + + + +/* PGPLOT interface functions */ +/* ========================== */ +static void ccpgqclp(int *clip){ + F77_INTEGER_TYPE CLIP; + F77_CALL(pgqclp)( INTEGER_ARG(&CLIP) ); + *clip = (int) CLIP; +} + +static void ccpgsclp(int clip){ + F77_INTEGER_TYPE CLIP; + CLIP = (F77_INTEGER_TYPE) clip; + F77_CALL(pgsclp)( INTEGER_ARG(&CLIP) ); +} + +static void ccpgqid(int *id){ + F77_INTEGER_TYPE ID; + F77_CALL(pgqid)( INTEGER_ARG(&ID) ); + *id = (int) ID; +} + + +static void ccpgswin(float x1, float x2, float y1, float y2){ + F77_REAL_TYPE X1; + F77_REAL_TYPE X2; + F77_REAL_TYPE Y1; + F77_REAL_TYPE Y2; + + X1 = x1; + X2 = x2; + Y1 = y1; + Y2 = y2; + + F77_CALL(pgswin)( REAL_ARG(&X1), REAL_ARG(&X2), REAL_ARG(&Y1), + REAL_ARG(&Y2) ); +} + +static void ccpgline(int n, float xpts[], float ypts[] ){ + F77_INTEGER_TYPE N; + F77_REAL_TYPE *XX; + F77_REAL_TYPE *YY; + int i; + + XX = (F77_REAL_TYPE *) astMalloc( sizeof( F77_REAL_TYPE )*(size_t) n ); + YY = (F77_REAL_TYPE *) astMalloc( sizeof( F77_REAL_TYPE )*(size_t) n ); + + if( astOK ){ + + for( i = 0; i < n; i++ ){ + XX[ i ] = (F77_REAL_TYPE) xpts[ i ]; + YY[ i ] = (F77_REAL_TYPE) ypts[ i ]; + } + + N = (F77_INTEGER_TYPE) n; + + F77_CALL(pgline)( INTEGER_ARG(&N), REAL_ARRAY_ARG(XX), + REAL_ARRAY_ARG(YY) ); + + XX = (F77_REAL_TYPE *) astFree( (void *) XX ); + YY = (F77_REAL_TYPE *) astFree( (void *) YY ); + } +} + +static void ccpgpoly(int n, float xpts[], float ypts[] ){ + F77_INTEGER_TYPE N; + F77_REAL_TYPE *XX; + F77_REAL_TYPE *YY; + int i; + + XX = (F77_REAL_TYPE *) astMalloc( sizeof( F77_REAL_TYPE )*(size_t) n ); + YY = (F77_REAL_TYPE *) astMalloc( sizeof( F77_REAL_TYPE )*(size_t) n ); + + if( astOK ){ + + for( i = 0; i < n; i++ ){ + XX[ i ] = (F77_REAL_TYPE) xpts[ i ]; + YY[ i ] = (F77_REAL_TYPE) ypts[ i ]; + } + + N = (F77_INTEGER_TYPE) n; + + F77_CALL(pgpoly)( INTEGER_ARG(&N), REAL_ARRAY_ARG(XX), + REAL_ARRAY_ARG(YY) ); + + XX = (F77_REAL_TYPE *) astFree( (void *) XX ); + YY = (F77_REAL_TYPE *) astFree( (void *) YY ); + } +} + +static void ccpgqwin(float *x1, float *x2, float *y1, float *y2){ + F77_REAL_TYPE X1; + F77_REAL_TYPE X2; + F77_REAL_TYPE Y1; + F77_REAL_TYPE Y2; + + F77_CALL(pgqwin)( REAL_ARG(&X1), REAL_ARG(&X2), REAL_ARG(&Y1), + REAL_ARG(&Y2) ); + *x1 = (float) X1; + *x2 = (float) X2; + *y1 = (float) Y1; + *y2 = (float) Y2; +} + +static void ccpgqch(float *ch){ + F77_REAL_TYPE CH; + F77_CALL(pgqch)( REAL_ARG(&CH) ); + *ch = (float) CH; +} + +static void ccpgqcf(int *cf){ + F77_INTEGER_TYPE CF; + F77_CALL(pgqcf)( INTEGER_ARG(&CF) ); + *cf = (int) CF; +} + +static void ccgrsyds( int *list, int *nlist, const char *text, int tlen, + int font ){ + F77_INTEGER_TYPE *LIST; + F77_INTEGER_TYPE NLIST; + DECLARE_CHARACTER(LTEXT,MXSTRLEN); + F77_INTEGER_TYPE FONT; + int ftext_length; + int i; + + ftext_length = tlen; + if( ftext_length > LTEXT_length ) ftext_length = LTEXT_length; + astStringExport( text, LTEXT, ftext_length ); + + LIST = (F77_INTEGER_TYPE *) astMalloc( sizeof( F77_INTEGER_TYPE )*(size_t) ftext_length ); + + if( astOK ){ + + FONT = (F77_INTEGER_TYPE) font; + + F77_CALL(grsyds)( INTEGER_ARRAY_ARG(LIST), INTEGER_ARG(&NLIST), + CHARACTER_ARG(LTEXT), INTEGER_ARG(&FONT) + TRAIL_ARG(ftext) ); + + *nlist = (int) NLIST; + for( i = 0; i < ftext_length; i++ ){ + list[ i ] = (int) LIST[ i ]; + } + + LIST = (F77_INTEGER_TYPE *) astFree( (void *) LIST ); + } +} + +static void ccgrsymk( int type, int font, int *symbol ){ + F77_INTEGER_TYPE TYPE; + F77_INTEGER_TYPE FONT; + F77_INTEGER_TYPE SYMBOL; + + TYPE = (F77_INTEGER_TYPE) type; + FONT = (F77_INTEGER_TYPE) font; + F77_CALL(grsymk)( INTEGER_ARG(&TYPE), INTEGER_ARG(&FONT), + INTEGER_ARG(&SYMBOL) ); + *symbol = (int) SYMBOL; +} + + +static void ccgrsyxd( int symbol, int *xygrid, int *unused ){ + F77_INTEGER_TYPE SYMBOL; + DECLARE_INTEGER_ARRAY(XYGRID,300); + F77_LOGICAL_TYPE UNUSED; + int i; + + SYMBOL = (F77_INTEGER_TYPE) symbol; + F77_CALL(grsyxd)( INTEGER_ARG(&SYMBOL), INTEGER_ARRAY_ARG(XYGRID), + LOGICAL_ARG(&UNUSED) ); + + *unused = ( UNUSED == F77_TRUE ); + for( i = 0; i < 5; i++ ) xygrid[ i ] = (int) XYGRID[ i ]; + for( ; i < 300; i++ ){ + xygrid[ i ] = (int) XYGRID[ i ]; + i++; + if( ( xygrid[ i ] = (int) XYGRID[ i ] ) == -64 ) break; + } +} + +static void ccpgupdt( void ){ + F77_CALL(pgupdt)(); +} + +static void ccpgqci(int *ci){ + F77_INTEGER_TYPE CI; + F77_CALL(pgqci)( INTEGER_ARG(&CI) ); + *ci = (int) CI; +} + +static void ccpgqls(int *ls){ + F77_INTEGER_TYPE LS; + F77_CALL(pgqls)( INTEGER_ARG(&LS) ); + *ls = (int) LS; +} + +static void ccpgqlw(int *lw){ + F77_INTEGER_TYPE LW; + F77_CALL(pgqlw)( INTEGER_ARG(&LW) ); + *lw = (int) LW; +} + +static void ccpgscf(int cf){ + F77_INTEGER_TYPE CF; + CF = (F77_INTEGER_TYPE) cf; + F77_CALL(pgscf)( INTEGER_ARG(&CF) ); +} + +static void ccpgsch(float ch){ + F77_REAL_TYPE CH; + CH = (F77_REAL_TYPE) ch; + F77_CALL(pgsch)( REAL_ARG(&CH) ); +} + +static void ccpgsci(int ci){ + F77_INTEGER_TYPE CI; + CI = (F77_INTEGER_TYPE) ci; + F77_CALL(pgsci)( INTEGER_ARG(&CI) ); +} + +static void ccpgsls(int ls){ + F77_INTEGER_TYPE LS; + LS = (F77_INTEGER_TYPE) ls; + F77_CALL(pgsls)( INTEGER_ARG(&LS) ); +} + +static void ccpgslw(int lw){ + F77_INTEGER_TYPE LW; + LW = (F77_INTEGER_TYPE) lw; + F77_CALL(pgslw)( INTEGER_ARG(&LW) ); +} + +static void ccpgqvsz(int units, float *x1, float *x2, float *y1, float *y2){ + F77_INTEGER_TYPE UNITS; + F77_REAL_TYPE X1; + F77_REAL_TYPE X2; + F77_REAL_TYPE Y1; + F77_REAL_TYPE Y2; + + UNITS = (F77_INTEGER_TYPE) units; + F77_CALL(pgqvsz)( INTEGER_ARG(&UNITS), REAL_ARG(&X1), REAL_ARG(&X2), + REAL_ARG(&Y1), REAL_ARG(&Y2) ); + *x1 = (float) X1; + *x2 = (float) X2; + *y1 = (float) Y1; + *y2 = (float) Y2; +} + + + +/* Fortran interfaces for public functions in this module. */ +/* ======================================================= */ + + +F77_LOGICAL_FUNCTION(pg3d_findnearest)( INTEGER(N), + REAL_ARRAY(X), + REAL_ARRAY(Y), + REAL_ARRAY(Z), + INTEGER(ICLOSE) ){ + GENPTR_INTEGER(N) + GENPTR_REAL_ARRAY(X) + GENPTR_REAL_ARRAY(Y) + GENPTR_REAL_ARRAY(Z) + GENPTR_INTEGER(ICLOSE) + return PG3DFindNearest( *N, X, Y, Z, ICLOSE ) ? F77_TRUE : F77_FALSE; +} + + + +F77_LOGICAL_FUNCTION(pg3d_setcamera)( REAL_ARRAY(EYE), + REAL_ARRAY(TARGET), + REAL_ARRAY(UP), + REAL(SCREEN) ){ + GENPTR_REAL_ARRAY(EYE) + GENPTR_REAL_ARRAY(TARGET) + GENPTR_REAL_ARRAY(UP) + GENPTR_REAL(SCREEN) + return PG3DSetCamera( EYE, TARGET, UP, *SCREEN ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_getcamera)( REAL_ARRAY(EYE), + REAL_ARRAY(TARGET), + REAL_ARRAY(UP), + REAL(SCREEN) ){ + GENPTR_REAL_ARRAY(EYE) + GENPTR_REAL_ARRAY(TARGET) + GENPTR_REAL_ARRAY(UP) + GENPTR_REAL(SCREEN) + return PG3DGetCamera( EYE, TARGET, UP, SCREEN ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_rotatetarget)( INTEGER(AXIS), REAL(ANGLE) ){ + GENPTR_INTEGER(AXIS) + GENPTR_REAL(ANGLE) + return PG3DRotateTarget( *AXIS, *ANGLE ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_autocamera)( REAL_ARRAY(LBND), + REAL_ARRAY(UBND) ){ + GENPTR_REAL_ARRAY(LBND) + GENPTR_REAL_ARRAY(UBND) + return PG3DAutoCamera( LBND, UBND ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_seteye)( REAL_ARRAY(EYE) ){ + GENPTR_REAL_ARRAY(EYE) + return PG3DSetEye( EYE ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_setup)( REAL_ARRAY(UP) ){ + GENPTR_REAL_ARRAY(UP) + return PG3DSetUp( UP ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_rotateeye)( INTEGER(DIR), REAL(ANGLE) ){ + GENPTR_INTEGER(DIR) + GENPTR_REAL(ANGLE) + return PG3DRotateEye( *DIR, *ANGLE ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(pg3d_forward)( REAL(DISTANCE) ){ + GENPTR_REAL(DISTANCE) + return PG3DForward( *DISTANCE ) ? F77_TRUE : F77_FALSE; +} + +F77_LOGICAL_FUNCTION(ast_g3dmark)( INTEGER(N), + REAL_ARRAY(X), + REAL_ARRAY(Y), + REAL_ARRAY(Z), + INTEGER(TYPE), + REAL_ARRAY(NORM)){ + GENPTR_INTEGER(N) + GENPTR_REAL_ARRAY(X) + GENPTR_REAL_ARRAY(Y) + GENPTR_REAL_ARRAY(Z) + GENPTR_INTEGER(TYPE) + GENPTR_REAL_ARRAY(NORM) + return astG3DMark( *N, X, Y, Z, *TYPE, NORM ) ? F77_TRUE : F77_FALSE; + +} + +F77_LOGICAL_FUNCTION(ast_g3dline)( INTEGER(N), + REAL_ARRAY(X), + REAL_ARRAY(Y), + REAL_ARRAY(Z) ){ + GENPTR_INTEGER(N) + GENPTR_REAL_ARRAY(X) + GENPTR_REAL_ARRAY(Y) + GENPTR_REAL_ARRAY(Z) + return astG3DLine( *N, X, Y, Z ) ? F77_TRUE : F77_FALSE; + +} + + +F77_INTEGER_FUNCTION(ast_g3dtext)( CHARACTER(TEXT), + REAL_ARRAY(REF), + CHARACTER(JUST), + REAL_ARRAY(UP), + REAL_ARRAY(NORM) + TRAIL(TEXT) + TRAIL(JUST) ){ + GENPTR_CHARACTER(TEXT) + GENPTR_REAL_ARRAY(REF) + GENPTR_CHARACTER(JUST) + GENPTR_REAL_ARRAY(UP) + GENPTR_REAL_ARRAY(NORM) + F77_INTEGER_TYPE(RESULT); + char *text, *just, *p; + + text = astString( TEXT, TEXT_length ); + just = astString( JUST, JUST_length ); + +/* Ignore trailing spaces in the text */ + p = text + TEXT_length; + while( !*p || *p == ' ' ) *(p--) = 0; + + if( astOK ) { + RESULT = (F77_INTEGER_TYPE) astG3DText( text, REF, just, UP, NORM ); + } else { + RESULT = 0; + } + + (void) astFree( text ); + (void) astFree( just ); + + return RESULT; +} + +F77_INTEGER_FUNCTION(ast_g3dtxext)( CHARACTER(TEXT), + REAL_ARRAY(REF), + CHARACTER(JUST), + REAL_ARRAY(UP), + REAL_ARRAY(NORM), + REAL_ARRAY(XB), + REAL_ARRAY(YB), + REAL_ARRAY(ZB), + REAL_ARRAY(BL) + TRAIL(TEXT) + TRAIL(JUST) ){ + GENPTR_CHARACTER(TEXT) + GENPTR_REAL_ARRAY(REF) + GENPTR_CHARACTER(JUST) + GENPTR_REAL_ARRAY(UP) + GENPTR_REAL_ARRAY(NORM) + GENPTR_REAL_ARRAY(XB) + GENPTR_REAL_ARRAY(YB) + GENPTR_REAL_ARRAY(ZB) + GENPTR_REAL_ARRAY(BL) + F77_INTEGER_TYPE(RESULT); + char *text, *just, *p; + + text = astString( TEXT, TEXT_length ); + just = astString( JUST, JUST_length ); + +/* Ignore trailing spaces in the text */ + p = text + TEXT_length; + while( !*p || *p == ' ' ) *(p--) = 0; + + if( astOK ) { + RESULT = (F77_INTEGER_TYPE) astG3DTxExt( text, REF, just, UP, NORM, + XB, YB, ZB, BL ); + } else { + RESULT = 0; + } + + (void) astFree( text ); + (void) astFree( just ); + + return RESULT; +} + + |